Libraries

library(tidyverse)
library(dplyr)
library(ggplot2)
library(httr) # read out Dropbox folders
library(vegan)
library(readxl)

Make species x trait matrix

Greenhouse traits

  • height, leaf dry matter content, specific leaf area, root mass fraction, relative growth rate, coarse root diameter, root density, specific root length of fine roots, specific root length of coarse roots

Field traits

  • height, leaf dry matter content, specific leaf area, seed mass, leaf C, leaf N

“H1: Pairing field results with a greenhouse 15 N experiment will allow us to relate species responses to their ability to uptake organic N”

“In addition, we will conduct a greenhouse experiment to isolate the mechanism (mineralized N vs organic N uptake rates ) by which compost may affect species composition”

Workflow plan:

  • overlay species trait data as vectors on the NMDS

    • only greenhouse traits available (only sla data from field)

      • use PC scores as composite trait axes OR

      • average the traits for each species

Read in and out matrices from traitOrdination code

Read in trait data

# # read in greenhouse trait data
# traits.gh <- read.csv("https://www.dropbox.com/scl/fi/c8vk31a807xg48jez1j03/GreenhouseTraits.csv?rlkey=ca736ea27k79mo7h8dbn67qiq&st=ya1ck6p7&dl=1")
# 
# # read in field trait data
# # download.file("https://www.dropbox.com/scl/fi/trqrnz54dkjoa9do4tle5/leaf-area-data_NG.xlsx?rlkey=s0kic2a5yqknikc4icek8y7rn&st=dl4x634h&dl=1",destfile = "field_sla.xlsx")
# traits.sla.field <- 
#   read_excel("field_sla.xlsx",col_names = TRUE,col_types = "text")
# 
# rda(traits.gh, scale = TRUE)

Investigate trait data, looking in Greenhouse trait folder

Trait data is identical. Will clean data in

# dropbox.main <- read.csv("https://www.dropbox.com/scl/fi/c8vk31a807xg48jez1j03/GreenhouseTraits.csv?rlkey=ca736ea27k79mo7h8dbn67qiq&st=0h1bs53j&dl=1")
# 
# dropbox.gh <- read.csv("https://www.dropbox.com/scl/fi/67aaubdydiy4ixffmwvfe/GreenhouseTraits.csv?rlkey=rm2eqeqome7hgoedhnal0gx6d&st=vkym6evx&dl=1")
# 
# all.equal(dropbox.main, dropbox.gh)
# identical(dropbox.main, dropbox.gh)
traits.cleaned <- read.csv("data/GreenhouseTraits_corrected_20240212.csv") %>%
  mutate(
    Fresh.leaf.mass..g. = as.numeric(ifelse(
      Fresh.leaf.mass..g. == "Skipped accidentally", NA, Fresh.leaf.mass..g.
    )),
    Dry.leaf.mass..g. = as.numeric(ifelse(
      Dry.leaf.mass..g. == "No sample", NA, Dry.leaf.mass..g.
    )),
    Root.dry.biomass..g. = as.numeric(ifelse(
      Root.dry.biomass..g. == "roots lost", NA, Root.dry.biomass..g.
    )),
    Root.volume..cm3. = as.numeric(ifelse(
      Root.volume..cm3. == "not scanned", NA, Root.volume..cm3.
    ))
  ) 
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `Root.dry.biomass..g. = as.numeric(ifelse(Root.dry.biomass..g. == "roots lost", NA, Root.dry.biomass..g.))`.
Caused by warning:
! NAs introduced by coercion

Summarize trait data (GH) for each species

means

# make trait species ID match matrix data (notes shown below) -------
traits.cleaned <- traits.cleaned %>%
  mutate(
    ID = ifelse(
      ID == "Agoseris", "AGSP", ifelse(
        ID == "AVEBAR", "AVBA", ifelse(
          ID == "BRDR", "BRDI", ID
        )
      )
    )
  )

# summary(traits.cleaned)
traits.means <- traits.cleaned %>%
  group_by(ID) %>%
  summarise(
    across(4:(ncol(traits.gh) - 1), list(mean = ~mean(.x, na.rm = TRUE)
  ))) %>%
  rename(
    Height = Height..cm._mean,
    FreshLeafMass = Fresh.leaf.mass..g._mean,
    DryLeafMass = Dry.leaf.mass..g._mean,
    LDMC = LDMC_mean, # Leaf dry matter content (LDMC, the ratio of leaf dry mass to fresh mass)
    LeafArea = Leaf.Area..cm2._mean,
    SLA = SLA..cm2.g._mean,
    ShootDryBiomass = Shoot.dry.biomass..g._mean,
    RootDryBiomass = Root.dry.biomass..g._mean,
    TotalBiomass = Total.biomass..g._mean,
    RMF = RMF_mean, # Root mass fraction (RMF) is a plant trait that measures the proportion of a plant's dry mass that is in its roots
    RootVol = Root.volume..cm3._mean,
    RootDensity = Root.density..g.cm3._mean,
    CoarseRootDiameter = Coarse.root.diameter..mm._mean,
    RootLength = Length..mm._mean,
    FineRootLength = Fine.root.length..mm._mean,
    CoarseRootLength = Coarse.root.length..mm._mean,
    CoarseRootSpecLength = Coarse.root.specific.length..cm.g._mean,
    FineRootSpecLength = Fine.root.specific.length..cm.g._mean,
    PropFineRoots = Proportion.fine.roots_mean
  )
  

# make site by species matrix match traits species
matrix.names <- data.frame(colnames(matrix.bray)) #species comp (75 count)
trait.names <- data.frame(traits.means$ID) #trait species (80 count)

intersect.names <- intersect(colnames(matrix.bray), traits.means$ID) # same species (43 count)
setdiff(colnames(matrix.bray), traits.means$ID)
 [1] "ASSP"  "AST1"  "AST2"  "AST3"  "CIQU"  "CRTI"  "CYEC"  "DACA"  "DIMU"  "GAGR"  "GAPA"  "GAPH"  "HYSP"  "JUBU"  "LYHY"  "MAD1"  "MAD2"  "NAPU"  "PAVI"  "SABI1"
[21] "SABI2" "SIGA"  "THGR"  "TRSP"  "UNBU"  "UNF1"  "UNF3"  "UNF4"  "UNF8"  "UNFR"  "UNGR"  "XAST" 
setdiff(traits.means$ID, colnames(matrix.bray))
 [1] "ACMI"      "ANARp"     "AVFA"      "BRCA"      "BRHOp"     "BRNIf"     "BRNIp"     "CLPUf"     "CLPUp"     "CYDA"      "Crassula"  "ESCA"      "FEMI"     
[14] "FEMY"      "GITRf"     "GITRp"     "HYGL"      "LACA"      "LENIf"     "LENIp"     "LOPU"      "LUBI"      "Leontodon" "MAELf"     "MAELp"     "MICA"     
[27] "NEMA"      "PLERf"     "PLERp"     "RUPU"      "Sanicula"  "TRCI"      "TRHIpi"    "TRWIf"     "TRWIp"     "TRWIpi"    "VIVA"     
# check matrix codes to see if same species are named different things
unique.matrix.species <- cover.dat %>%
  dplyr::select(code4, species) %>%
  summarise(
    code4 = unique(code4),
    species = unique(species)
  )
Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0.
Please use `reframe()` instead.
When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly.
unique.trait.species <- traits.cleaned %>%
  dplyr::select(Taxon, ID) %>%
  distinct(ID, .keep_all = TRUE)
  

# write traits.means csv ----
# write.csv(traits.means, "data/traits/all_sp_trait_means.csv")

See if I have to match names with traits ever year (ANS: All Same Species)

# # all years -------------
# # make site by species matrix match traits species
# matrix.names <- data.frame(colnames(matrix.bray)) #species comp (75 count)
# trait.names <- data.frame(traits.means$ID) #trait species (80 count)
# 
# intersect.names <- intersect(colnames(matrix.bray), traits.means$ID) # same species (43 count)
# setdiff(colnames(matrix.bray), traits.means$ID)
# setdiff(traits.means$ID, colnames(matrix.bray))
# 
# # check matrix codes to see if same species are named different things
# unique.matrix.species <- cover.dat %>%
#   dplyr::select(code4, species) %>%
#   summarise(
#     code4 = unique(code4),
#     species = unique(species)
#   )
# 
# unique.trait.species <- traits.cleaned %>%
#   dplyr::select(Taxon, ID) %>%
#   distinct(ID, .keep_all = TRUE)
#   
# # 2019 -------------
# data.frame(colnames(matrix.bray.2019)) #species comp (75 count)
# data.frame(colnames(matrix.bray.2020)) #species comp (75 count)
# data.frame(colnames(matrix.bray.2021)) #species comp (75 count)
  • change Trait name: ‘Agoseris’ –> ‘Agoseris unknown’; assuming the same as ‘AGSP’ –> ‘Agoseris sp.’ in matrix data (change to matrix name)

  • What’s the difference between:

    • ‘ANAR’ and ‘ANARp’ in trait data?

    • ‘BRHO’ and ‘BRHOp’ in trait data?

    • ‘BRNIf’ and ‘BRNIp’ in trait data? (not in matrix data)

    • ‘CLPUf’ and ‘CLPUp’ in trait data? (not in matrix data)

    • ‘GITRf’ and ‘GITRp’ in trait data? (not in matrix data)

    • ‘LENIf’ and ‘LENIp’ in trait data? (not in matrix data)

    • ‘TRHI’ and ‘TRHIpi’ (same sp name) in trait data? (TRHI in matrix data)

    • ‘TRWIf’ and ‘TRWIp’ and ‘TRWIpi’ in trait data? (not in matrix data)

    • ‘Crassula’ and ‘Crassula tillaea’ (could they be the same?)

    • ‘Sanicula’ (unknown) and ‘SABI1’ or ‘SABI2’ (could they be the same?)

    • ‘MAELf’ (trait data) and ‘MAD1’ (Madia sp. 1 (“tall tarweed”)’ (could they be the same?)

    • ‘MAELp’ (trait data) and ‘MAD2’ (Madia sp. 1 (“small tarweed”)’ (could they be the same?)

    • ‘Trifolium eriocephalum’ (TRER) and ‘Triphysaria eriantha’ (TRER) (could they be the same?)

  • change ‘AVEBAR’ (trait data) to ‘AVBA’ (matrix data)

  • change BRDR –> BRDI

Overlay Trait Vectors onto NMDS

Aboveground Traits

  • Height

  • Leaf

    • FreshLeafMass

    • DryLeafMass

    • LDMC

      • Leaf dry matter content (LDMC, the ratio of leaf dry mass to fresh mass)
    • LeafArea

    • SLA

    • ShootDryBiomass

Belowground Traits

  • RootDryBiomass

  • RMF

    • Root mass fraction (RMF) is a plant trait that measures the proportion of a plant’s dry mass that is in its roots
  • RootVol

  • RootDensity

  • RootLength

  • PropFineRoots

  • Coarse Roots

    • CoarseRootDiameter

    • CoarseRootLength

    • CoarseRootSpecLength

  • Fine Roots

    • FineRootLength

    • FineRootSpecLength

  • TotalBiomass

ALL YEARS – LOW AND HIGH GRAZING

Prepare NMDS and Traits

Stress:

0.2011127
# subset nmds to match species names
nmds.comp.trait <- metaMDS(matrix.bray %>%
                             dplyr::select(intersect.names), 
                           k=2, trymax = 25)
Run 0 stress 0.2060005 
Run 1 stress 0.2019906 
... New best solution
... Procrustes: rmse 0.07567441  max resid 0.2449078 
Run 2 stress 0.2007527 
... New best solution
... Procrustes: rmse 0.08985478  max resid 0.2109131 
Run 3 stress 0.2094711 
Run 4 stress 0.2107847 
Run 5 stress 0.2089838 
Run 6 stress 0.2078775 
Run 7 stress 0.2027916 
Run 8 stress 0.2173911 
Run 9 stress 0.2059157 
Run 10 stress 0.2220001 
Run 11 stress 0.2079152 
Run 12 stress 0.2124366 
Run 13 stress 0.2050097 
Run 14 stress 0.202904 
Run 15 stress 0.2027187 
Run 16 stress 0.2032121 
Run 17 stress 0.2179617 
Run 18 stress 0.2028023 
Run 19 stress 0.2012207 
... Procrustes: rmse 0.02040594  max resid 0.1298012 
Run 20 stress 0.2051096 
Run 21 stress 0.2080723 
Run 22 stress 0.201363 
Run 23 stress 0.2029037 
Run 24 stress 0.2173911 
Run 25 stress 0.2079715 
*** Best solution was not repeated -- monoMDS stopping criteria:
    22: stress ratio > sratmax
     3: scale factor of the gradient < sfgrmin
nmds.comp.trait # pretty not great stress

Call:
metaMDS(comm = matrix.bray %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.2007527 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 2 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray %>% dplyr::select(intersect.names)’ 
stressplot(nmds.comp.trait)

plot(nmds.comp.trait, type="t")


nmds1 <- as.data.frame(scores(nmds.comp.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.comp.trait, choices=c(2), display=c("sites")))

nmds_dat_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# subset matrix and trait data to match names
traits.means.comp <- traits.means %>%
  filter(ID %in% intersect.names) 

# traits.means.comp2 <- traits.means.comp %>%
# dplyr::select(-ID)
rownames(traits.means.comp2) <- traits.means.comp$ID
Warning: Setting row names on a tibble is deprecated.
# trait vectors onto the NMDS
# envfit(nmds.comp.trait, traits.means.comp, permutations = 999)
# example from stack overflow: envfit(ord ~ var1 + var2 + var3, dune.spec, display="sp"), 'ord' is the nmds model, 'var1' is the trait1 i think?

colnames(traits.means.comp)
 [1] "ID"                   "Height"               "FreshLeafMass"        "DryLeafMass"          "LDMC"                 "LeafArea"             "SLA"                 
 [8] "ShootDryBiomass"      "RootDryBiomass"       "TotalBiomass"         "RMF"                  "RootVol"              "RootDensity"          "CoarseRootDiameter"  
[15] "RootLength"           "FineRootLength"       "CoarseRootLength"     "CoarseRootSpecLength" "FineRootSpecLength"   "PropFineRoots"       
vectors.nmds.comp.trait <- envfit(nmds.comp.trait ~ Height + 
                                    LeafArea +
                                    RMF, traits.means.comp, display = "sp") # ONLY Height, Leaf area, and RMF significant

#TEMPLATE: 
  # envfit(nmds.block.trait ~ Height + 
  #          FreshLeafMass +
  #          DryLeafMass +
  #          LDMC +
  #          LeafArea +
  #          SLA +
  #          ShootDryBiomass +
  #          RootDryBiomass +
  #          TotalBiomass +
  #          RMF +
  #          RootVol +
  #          RootDensity +
  #          CoarseRootDiameter +
  #          RootLength +
  #          FineRootLength +
  #          CoarseRootLength +
  #          CoarseRootSpecLength +
  #          FineRootSpecLength +
  #          PropFineRoots, traits.means.comp, display = "sp", na.rm = TRUE)

# is it different when you only do certain traits (above- vs. below-ground)? or can you just throw everything in there and it will tell you what is significant and you can subset from there?

# Looks like different subsets of traits put in are the same, so I shall proceed with the mega models and verify with Lauren

trait_vectors <- as.data.frame(vectors.nmds.comp.trait$vectors$arrows)

NMDS model: only Height, Leaf area, and RMF () found significant.

Plot

ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment") +
  custom_colors +
  scale_color_manual(
    values = c(
      "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
      "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
      "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
      "wet" = rgb(0, 0, 255, maxColorValue = 255),
      "dry" = rgb(183, 65, 14, maxColorValue = 255)
    )
  ) +
  geom_segment(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = NMDS1, y = NMDS2, label = rownames(vectors.nmds.comp.trait$vectors$arrows)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, color = as.factor(yr), fill = as.factor(yr))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) +
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Year")+
  geom_segment(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = NMDS1, y = NMDS2, label = rownames(vectors.nmds.comp.trait$vectors$arrows)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, fill = as.factor(ppt_trt), color = as.factor(ppt_trt))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) +
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)+
  geom_segment(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = NMDS1, y = NMDS2, label = rownames(vectors.nmds.comp.trait$vectors$arrows)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  fill = as.factor(grazing_hist), color = as.factor(grazing_hist))) +
  geom_point(shape = 21, size = 4, stroke = 0.5) +
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Grazing History") +
  geom_segment(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
    aes(x = NMDS1, y = NMDS2, label = rownames(vectors.nmds.comp.trait$vectors$arrows)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


# ggplot(nmds_dat_trait, aes(NMDS1, NMDS2,  color = as.factor(grazing_hist), fill = as.factor(yr))) +
#   geom_point(aes(fill = as.factor(yr)), shape = 21, size = 4, stroke = 1) +
#   stat_ellipse(aes(color = as.factor(yr)),
#                 geom = "polygon",
#                fill = NA,
#                size = 1) +
#   labs(title = "Grouped by Grazing History & Year") +
#   scale_color_manual(
#   values = c(
#     "low" = "cyan",
#     "high" = "brown",
#   "2019" = "salmon",
#   "2020" = "limegreen",
#   "2021" = "cornflowerblue")
#   ) +
#   geom_segment(
#     data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
#     aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
#     inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
#     arrow = arrow(length = unit(0.2, "cm")), 
#     color = "red", 
#     size = 1
#   ) +
#   geom_text(
#     data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
#     aes(x = NMDS1, y = NMDS2, label = rownames(vectors.nmds.comp.trait$vectors$arrows)), 
#     inherit.aes = FALSE,  # Avoids unwanted inheritance
#     hjust = -0.2, 
#     vjust = -0.2, 
#     color = "red",
#     size = 5
#   )
#   
# ggplot(nmds_dat_trait, aes(NMDS1, NMDS2, color = nut_trt, fill = as.factor(yr))) +
#   geom_point(shape = 21, size = 4, stroke = 1) +
#   stat_ellipse(aes(color = as.factor(nut_trt)),
#              geom = "polygon",
#              fill = NA,  # Makes the ellipse transparent inside
#              size = 1) +
#   labs(title = "Grouped by Nutrient Treatment & Year") +
#   scale_color_manual(
#   values = c(
#     "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
#     "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
#     "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
#     "wet" = rgb(0, 0, 255, maxColorValue = 255),
#     "dry" = rgb(183, 65, 14, maxColorValue = 255)
#   )
# ) +
#   geom_segment(
#     data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
#     aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
#     inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
#     arrow = arrow(length = unit(0.2, "cm")), 
#     color = "red", 
#     size = 1
#   ) +
#   geom_text(
#     data = as.data.frame(vectors.nmds.comp.trait$vectors$arrows), 
#     aes(x = NMDS1, y = NMDS2, label = rownames(vectors.nmds.comp.trait$vectors$arrows)), 
#     inherit.aes = FALSE,  # Avoids unwanted inheritance
#     hjust = -0.2, 
#     vjust = -0.2, 
#     color = "red",
#     size = 5
#   )

ALL YEARS – LOW AND HIGH GRAZING (Blocks)

Stress:

0.2353937

Prepare NMDS and Traits

# subset nmds to match species names
nmds.block.trait <- metaMDS(matrix.block.bray %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.2353937 
Run 1 stress 0.250124 
Run 2 stress 0.2353908 
... New best solution
... Procrustes: rmse 0.002559202  max resid 0.02324147 
Run 3 stress 0.2386994 
Run 4 stress 0.2487719 
Run 5 stress 0.2453858 
Run 6 stress 0.2574031 
Run 7 stress 0.2354028 
... Procrustes: rmse 0.002945858  max resid 0.02371427 
Run 8 stress 0.2563643 
Run 9 stress 0.2460121 
Run 10 stress 0.2644327 
Run 11 stress 0.2560224 
Run 12 stress 0.246987 
Run 13 stress 0.2354028 
... Procrustes: rmse 0.002938524  max resid 0.02369694 
Run 14 stress 0.2423148 
Run 15 stress 0.2463114 
Run 16 stress 0.2354028 
... Procrustes: rmse 0.002925757  max resid 0.02366134 
Run 17 stress 0.2353936 
... Procrustes: rmse 0.002546433  max resid 0.02319281 
Run 18 stress 0.2526558 
Run 19 stress 0.2499386 
Run 20 stress 0.2480986 
Run 21 stress 0.2497376 
Run 22 stress 0.2409873 
Run 23 stress 0.2385602 
Run 24 stress 0.2521044 
Run 25 stress 0.2378706 
*** Best solution was not repeated -- monoMDS stopping criteria:
    24: stress ratio > sratmax
     1: scale factor of the gradient < sfgrmin
nmds.block.trait # pretty not great stress

Call:
metaMDS(comm = matrix.block.bray %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.block.bray %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.2353908 
Stress type 1, weak ties
Best solution was not repeated after 25 tries
The best solution was from try 2 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.block.bray %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.block.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.block.trait, choices=c(2), display=c("sites")))

nmds_dat_block_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data
traits.means.comp 

# trait vectors onto the NMDS
vectors.nmds.block.trait <-
  envfit(nmds.block.trait ~ Height + 
           DryLeafMass +
           LeafArea +
           RootDryBiomass +
           RMF +
           RootDensity, traits.means.comp, display = "sp")
# ONLY Height, DryLeafMass, LeafArea, RMF significant (RootDryBiomass, RootDensity marginal)

trait_vectors <- as.data.frame(vectors.nmds.block.trait$vectors$arrows)

Plot

ggplot(nmds_dat_block_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Nutrient Treatment - Blocks w Traits") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_block_trait, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  labs(title = "Grouped by Precipitation Treatment - Blocks w Traits") +
  custom_colors +
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

NA
NA
NA
NA

All years - LOW GRAZING ONLY

Prepare NMDS and Traits

Stress:

0.1879671
# subset nmds to match species names
nmds.low.trait <- metaMDS(matrix.bray.low %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.2032274 
Run 1 stress 0.1911123 
... New best solution
... Procrustes: rmse 0.07305776  max resid 0.1904385 
Run 2 stress 0.2933553 
Run 3 stress 0.1890672 
... New best solution
... Procrustes: rmse 0.1307018  max resid 0.279877 
Run 4 stress 0.2104987 
Run 5 stress 0.208207 
Run 6 stress 0.2170339 
Run 7 stress 0.2019759 
Run 8 stress 0.1911123 
Run 9 stress 0.2124695 
Run 10 stress 0.2032282 
Run 11 stress 0.2020341 
Run 12 stress 0.1890672 
... Procrustes: rmse 3.79248e-06  max resid 8.350358e-06 
... Similar to previous best
Run 13 stress 0.2138031 
Run 14 stress 0.3881609 
Run 15 stress 0.2019912 
Run 16 stress 0.1915469 
Run 17 stress 0.2112419 
Run 18 stress 0.2084351 
Run 19 stress 0.1911123 
Run 20 stress 0.2105596 
*** Best solution repeated 1 times
nmds.low.trait 

Call:
metaMDS(comm = matrix.bray.low %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.low %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.1890672 
Stress type 1, weak ties
Best solution was repeated 1 time in 20 tries
The best solution was from try 3 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.low %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.low.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.low.trait, choices=c(2), display=c("sites")))

nmds_dat_low_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data: traits.means.comp 

# trait vectors onto the NMDS
vectors.nmds.low.trait <-
  envfit(nmds.low.trait ~ FreshLeafMass +
           RMF, traits.means.comp, display = "sp", na.rm = TRUE)
# ONLY FreshLeafMass (RMF marginal)

trait_vectors <- as.data.frame(vectors.nmds.low.trait$vectors$arrows)

Plot

ggplot(nmds_dat_low_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  labs(title = "2019-2021 (LOW) w Traits - Grouping by Nutrient Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  custom_colors + 
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_low_trait, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  labs(title = "2019-2021 (LOW) w Traits - Grouping by Precipitation Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  custom_colors + 
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

2019

Stress:

0.06290431

Prepare NMDS and Traits

# subset nmds to match species names
nmds.2019.trait <- metaMDS(matrix.bray.2019 %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.06471496 
Run 1 stress 0.06931106 
Run 2 stress 0.06874971 
Run 3 stress 0.3616162 
Run 4 stress 0.06264873 
... New best solution
... Procrustes: rmse 0.06539037  max resid 0.2367651 
Run 5 stress 0.09229892 
Run 6 stress 0.06471497 
Run 7 stress 0.06290424 
... Procrustes: rmse 0.005564852  max resid 0.0187599 
Run 8 stress 0.06816428 
Run 9 stress 0.06901458 
Run 10 stress 0.06471496 
Run 11 stress 0.07109362 
Run 12 stress 0.06459268 
Run 13 stress 0.08080796 
Run 14 stress 0.07203292 
Run 15 stress 0.06459267 
Run 16 stress 0.07780829 
Run 17 stress 0.07518585 
Run 18 stress 0.06264873 
... Procrustes: rmse 1.714225e-05  max resid 4.819798e-05 
... Similar to previous best
Run 19 stress 0.06931106 
Run 20 stress 0.07273526 
*** Best solution repeated 1 times
nmds.2019.trait 

Call:
metaMDS(comm = matrix.bray.2019 %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2019 %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.06264873 
Stress type 1, weak ties
Best solution was repeated 1 time in 20 tries
The best solution was from try 4 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2019 %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.2019.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.2019.trait, choices=c(2), display=c("sites")))

nmds_dat_2019_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data: traits.means.comp 


# trait vectors onto the NMDS
vectors.nmds.2019.trait <-
  envfit(nmds.2019.trait ~ Height + 
           DryLeafMass +
           LeafArea +
           RMF +
           RootDensity +
           CoarseRootDiameter, traits.means.comp, display = "sp", na.rm = TRUE)

Plot

ggplot(nmds_dat_2019_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2019 w Traits - Grouping by Nutrient Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

ggplot(nmds_dat_2019_trait, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2019 w Traits - Grouping by Precipitation Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

2020

Stress:

0.1512864

Prepare NMDS and Traits

# subset nmds to match species names
nmds.2020.trait <- metaMDS(matrix.bray.2020 %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.1512864 
Run 1 stress 0.16382 
Run 2 stress 0.1740134 
Run 3 stress 0.1512864 
... New best solution
... Procrustes: rmse 1.160478e-05  max resid 2.59613e-05 
... Similar to previous best
Run 4 stress 0.151653 
... Procrustes: rmse 0.01975231  max resid 0.06777473 
Run 5 stress 0.16382 
Run 6 stress 0.1601231 
Run 7 stress 0.151336 
... Procrustes: rmse 0.01055512  max resid 0.03081296 
Run 8 stress 0.1600829 
Run 9 stress 0.1922664 
Run 10 stress 0.171301 
Run 11 stress 0.1512864 
... New best solution
... Procrustes: rmse 1.626593e-05  max resid 3.63373e-05 
... Similar to previous best
Run 12 stress 0.151336 
... Procrustes: rmse 0.0105455  max resid 0.03079015 
Run 13 stress 0.1600829 
Run 14 stress 0.163364 
Run 15 stress 0.1512864 
... Procrustes: rmse 8.079558e-06  max resid 2.224799e-05 
... Similar to previous best
Run 16 stress 0.1740133 
Run 17 stress 0.1516619 
... Procrustes: rmse 0.01548936  max resid 0.05232438 
Run 18 stress 0.1714389 
Run 19 stress 0.175096 
Run 20 stress 0.16382 
*** Best solution repeated 2 times
nmds.2020.trait 

Call:
metaMDS(comm = matrix.bray.2020 %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2020 %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.1512864 
Stress type 1, weak ties
Best solution was repeated 2 times in 20 tries
The best solution was from try 11 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2020 %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.2020.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.2020.trait, choices=c(2), display=c("sites")))

nmds_dat_2020_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data: traits.means.comp 


# trait vectors onto the NMDS
vectors.nmds.2020.trait <-
  envfit(nmds.2020.trait ~ FreshLeafMass +
           LeafArea, traits.means.comp, display = "sp", na.rm = TRUE)

# ONLY FreshLeafMass, LeafArea

trait_vectors <- as.data.frame(vectors.nmds.2020.trait$vectors$arrows)

Plot

ggplot(nmds_dat_2020_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 w Traits - Grouping by Nutrient Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_2020_trait, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2020 w Traits - Grouping by Precipitation Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

2021

Prepare NMDS and Traits

Stress:

0.123061
# subset nmds to match species names
nmds.2021.trait <- metaMDS(matrix.bray.2021 %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.1234883 
Run 1 stress 0.123061 
... New best solution
... Procrustes: rmse 0.04524088  max resid 0.133887 
Run 2 stress 0.1556472 
Run 3 stress 0.1556472 
Run 4 stress 0.1510891 
Run 5 stress 0.133126 
Run 6 stress 0.1412774 
Run 7 stress 0.1234883 
... Procrustes: rmse 0.04524054  max resid 0.133303 
Run 8 stress 0.1234883 
... Procrustes: rmse 0.04524098  max resid 0.13329 
Run 9 stress 0.1331269 
Run 10 stress 0.1412774 
Run 11 stress 0.1331264 
Run 12 stress 0.1329969 
Run 13 stress 0.123061 
... Procrustes: rmse 7.588273e-06  max resid 2.28136e-05 
... Similar to previous best
Run 14 stress 0.1412774 
Run 15 stress 0.1412774 
Run 16 stress 0.1234883 
... Procrustes: rmse 0.04524105  max resid 0.1332899 
Run 17 stress 0.1234883 
... Procrustes: rmse 0.04524004  max resid 0.1333063 
Run 18 stress 0.1790971 
Run 19 stress 0.1513012 
Run 20 stress 0.123061 
... Procrustes: rmse 2.514183e-06  max resid 7.876099e-06 
... Similar to previous best
*** Best solution repeated 2 times
nmds.2021.trait 

Call:
metaMDS(comm = matrix.bray.2021 %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.2021 %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.123061 
Stress type 1, weak ties
Best solution was repeated 2 times in 20 tries
The best solution was from try 1 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.2021 %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.2021.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.2021.trait, choices=c(2), display=c("sites")))

nmds_dat_2021_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data: traits.means.comp 
rownames(traits.means.comp) <- traits.means.comp$ID
Warning: Setting row names on a tibble is deprecated.
# trait vectors onto the NMDS
vectors.nmds.2021.trait <-
  envfit(nmds.2021.trait ~ Height + 
           FreshLeafMass +
           LeafArea, na.omit(traits.means.comp), display = "sp", na.rm = TRUE)

# (Height, FreshLeafMass, LeafArea marginal)

trait_vectors <- as.data.frame(vectors.nmds.2021.trait$vectors$arrows)

Plot

ggplot(nmds_dat_2021_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 w Traits - Grouping by Nutrient Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_2021_trait, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 w Traits - Grouping by Precipitation Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

2021 – Blocks

Stress:

0.170799

Prepare NMDS and Traits

# subset nmds to match species names
nmds.2021.block.trait <- metaMDS(matrix.bray.block.2021 %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.170799 
Run 1 stress 0.2052476 
Run 2 stress 0.170799 
... New best solution
... Procrustes: rmse 9.313132e-06  max resid 3.473702e-05 
... Similar to previous best
Run 3 stress 0.2060774 
Run 4 stress 0.1873003 
Run 5 stress 0.2046024 
Run 6 stress 0.206467 
Run 7 stress 0.2180152 
Run 8 stress 0.1709819 
... Procrustes: rmse 0.007084111  max resid 0.03059497 
Run 9 stress 0.1797966 
Run 10 stress 0.170799 
... Procrustes: rmse 8.637585e-06  max resid 3.219545e-05 
... Similar to previous best
Run 11 stress 0.1797966 
Run 12 stress 0.1914994 
Run 13 stress 0.1951365 
Run 14 stress 0.1996107 
Run 15 stress 0.196785 
Run 16 stress 0.170799 
... New best solution
... Procrustes: rmse 6.097064e-06  max resid 2.279654e-05 
... Similar to previous best
Run 17 stress 0.214524 
Run 18 stress 0.1709819 
... Procrustes: rmse 0.007078194  max resid 0.03057796 
Run 19 stress 0.189269 
Run 20 stress 0.1939681 
*** Best solution repeated 1 times
nmds.2021.block.trait 

Call:
metaMDS(comm = matrix.bray.block.2021 %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.block.2021 %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.170799 
Stress type 1, weak ties
Best solution was repeated 1 time in 20 tries
The best solution was from try 16 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.block.2021 %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.2021.block.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.2021.block.trait, choices=c(2), display=c("sites")))

nmds_dat_2021_block_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data: traits.means.comp 


# trait vectors onto the NMDS
vectors.nmds.2021.block.trait <-
  envfit(nmds.2021.block.trait ~ DryLeafMass +
           LeafArea, traits.means.comp, display = "sp", na.rm = TRUE)

# ONLY DryLeafMass, LeafArea

trait_vectors <- as.data.frame(vectors.nmds.2021.block.trait$vectors$arrows)

Plot

ggplot(nmds_dat_2021_block_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block) w Traits - Grouping by Nutrient Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_2021_block_trait, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block) w Traits - Grouping by Precipitation Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

2021 – Blocks (LOW)

Stress:

0.1299711

Prepare NMDS and Traits

# subset nmds to match species names
nmds.2021.block.low.trait <- metaMDS(matrix.bray.block.2021.low %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.1299711 
Run 1 stress 0.1299712 
... Procrustes: rmse 5.590124e-05  max resid 0.0001635787 
... Similar to previous best
Run 2 stress 0.1299712 
... Procrustes: rmse 4.398462e-05  max resid 0.0001319322 
... Similar to previous best
Run 3 stress 0.1627521 
Run 4 stress 0.1299711 
... Procrustes: rmse 1.009167e-05  max resid 3.112151e-05 
... Similar to previous best
Run 5 stress 0.162752 
Run 6 stress 0.1299711 
... Procrustes: rmse 1.406545e-05  max resid 4.211068e-05 
... Similar to previous best
Run 7 stress 0.1299711 
... Procrustes: rmse 7.661138e-06  max resid 1.674758e-05 
... Similar to previous best
Run 8 stress 0.18467 
Run 9 stress 0.2001228 
Run 10 stress 0.1602444 
Run 11 stress 0.1299712 
... Procrustes: rmse 4.253368e-05  max resid 0.0001252648 
... Similar to previous best
Run 12 stress 0.1431163 
Run 13 stress 0.2111627 
Run 14 stress 0.1431163 
Run 15 stress 0.2104642 
Run 16 stress 0.1299712 
... Procrustes: rmse 3.767893e-05  max resid 0.0001028459 
... Similar to previous best
Run 17 stress 0.1431163 
Run 18 stress 0.1785202 
Run 19 stress 0.1299711 
... New best solution
... Procrustes: rmse 8.487148e-06  max resid 2.52772e-05 
... Similar to previous best
Run 20 stress 0.1602445 
*** Best solution repeated 1 times
nmds.2021.block.low.trait 

Call:
metaMDS(comm = matrix.bray.block.2021.low %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.block.2021.low %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.1299711 
Stress type 1, weak ties
Best solution was repeated 1 time in 20 tries
The best solution was from try 19 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.block.2021.low %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.2021.block.low.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.2021.block.low.trait, choices=c(2), display=c("sites")))

nmds_dat_2021_block_low_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data: traits.means.comp 


# trait vectors onto the NMDS
vectors.nmds.2021.block.low.trait <-
  envfit(nmds.2021.block.low.trait ~ FreshLeafMass, traits.means.comp, display = "sp", na.rm = TRUE)

# ONLY FreshLeafMass

trait_vectors <- as.data.frame(vectors.nmds.2021.block.low.trait$vectors$arrows)

Plot

ggplot(nmds_dat_2021_block_low_trait, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; LOW) w Trait - Grouping by Nutrient Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )


ggplot(nmds_dat_2021_block_low_trait, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; LOW) w Trait - Grouping by Precipitation Treatment") + 
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
) +
  geom_segment(
    data = trait_vectors, 
    aes(x = 0, y = 0, xend = NMDS1, yend = NMDS2), 
    inherit.aes = FALSE,  # 🚀 Prevents it from looking for 'nut_trt'
    arrow = arrow(length = unit(0.2, "cm")), 
    color = "red", 
    size = 1
  ) +
  geom_text(
    data = trait_vectors, 
    aes(x = NMDS1, y = NMDS2, label = rownames(trait_vectors)), 
    inherit.aes = FALSE,  # Avoids unwanted inheritance
    hjust = -0.2, 
    vjust = -0.2, 
    color = "red",
    size = 5
  )

2021 – Blocks (HIGH)

Prepare NMDS and Traits

# subset nmds to match species names
nmds.2021.block.high.trait <- metaMDS(matrix.bray.block.2021.high %>%
                             dplyr::select(intersect.names), , k=2, trymax = 25)
Run 0 stress 0.1416462 
Run 1 stress 0.1595099 
Run 2 stress 0.1867893 
Run 3 stress 0.2747088 
Run 4 stress 0.1867893 
Run 5 stress 0.1416462 
... New best solution
... Procrustes: rmse 3.289538e-05  max resid 8.812783e-05 
... Similar to previous best
Run 6 stress 0.1867893 
Run 7 stress 0.1416461 
... New best solution
... Procrustes: rmse 0.0004825076  max resid 0.00160539 
... Similar to previous best
Run 8 stress 0.1416461 
... Procrustes: rmse 0.0004023531  max resid 0.00133908 
... Similar to previous best
Run 9 stress 0.1595099 
Run 10 stress 0.1867893 
Run 11 stress 0.15951 
Run 12 stress 0.1867893 
Run 13 stress 0.1416461 
... Procrustes: rmse 7.442382e-05  max resid 0.000245897 
... Similar to previous best
Run 14 stress 0.1416461 
... Procrustes: rmse 4.391587e-05  max resid 0.000145225 
... Similar to previous best
Run 15 stress 0.1595099 
Run 16 stress 0.141646 
... New best solution
... Procrustes: rmse 0.0002924508  max resid 0.0009736183 
... Similar to previous best
Run 17 stress 0.1595099 
Run 18 stress 0.1416461 
... Procrustes: rmse 0.000208078  max resid 0.0006900715 
... Similar to previous best
Run 19 stress 0.141646 
... Procrustes: rmse 0.0002689142  max resid 0.0008954326 
... Similar to previous best
Run 20 stress 0.1416463 
... Procrustes: rmse 0.0002338219  max resid 0.0007719694 
... Similar to previous best
*** Best solution repeated 4 times
nmds.2021.block.high.trait 

Call:
metaMDS(comm = matrix.bray.block.2021.high %>% dplyr::select(intersect.names),      k = 2, trymax = 25) 

global Multidimensional Scaling using monoMDS

Data:     matrix.bray.block.2021.high %>% dplyr::select(intersect.names) 
Distance: bray 

Dimensions: 2 
Stress:     0.141646 
Stress type 1, weak ties
Best solution was repeated 4 times in 20 tries
The best solution was from try 16 (random start)
Scaling: centring, PC rotation, halfchange scaling 
Species: expanded scores based on ‘matrix.bray.block.2021.high %>% dplyr::select(intersect.names)’ 
nmds1 <- as.data.frame(scores(nmds.2021.block.high.trait, choices=c(1), display=c("sites")))
nmds2 <- as.data.frame(scores(nmds.2021.block.high.trait, choices=c(2), display=c("sites")))

nmds_dat_2021_block_high_trait <- cbind(nmds1, nmds2) %>%
  as.data.frame() %>%  # Ensure it's a data frame
  rownames_to_column(var = "site_id") %>%  # Move row names into a new column
  separate(site_id, into = c("nut_trt", "ppt_trt", "yr", "grazing_hist"), sep = "_")


# trait data: traits.means.comp 


# trait vectors onto the NMDS
vectors.nmds.2021.block.high.trait <-
  envfit(nmds.2021.block.high.trait ~ Height + 
           FreshLeafMass +
           DryLeafMass +
           LDMC +
           LeafArea +
           SLA +
           ShootDryBiomass +
           RootDryBiomass +
           TotalBiomass +
           RMF +
           RootVol +
           RootDensity +
           CoarseRootDiameter +
           RootLength +
           FineRootLength +
           CoarseRootLength +
           CoarseRootSpecLength +
           FineRootSpecLength +
           PropFineRoots, traits.means.comp, display = "sp", na.rm = TRUE)

# None

trait_vectors <- as.data.frame(vectors.nmds.2021.block.high.trait$vectors$arrows)

Plot

ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  fill = nut_trt, color = nut_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; HIGH) - Grouping by Nutrient Treatment") +
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)


ggplot(nmds_2021_dat.block.high, aes(NMDS1, NMDS2,  fill = ppt_trt, color = ppt_trt)) +
  geom_point(shape = 21, size = 4, stroke = 0.5) + 
  custom_colors + 
  labs(title = "2021 (Block; HIGH) - Grouping by Precipitation Treatment") +
  stat_ellipse(type = "norm", size = 1, alpha = 0.5) + # Ellipses for each group
  scale_color_manual(
  values = c(
    "control" = rgb(220, 220, 220, maxColorValue = 255),      # Lighter Gray
    "+N fertilizer" = rgb(140, 40, 150, maxColorValue = 255), # Vibrant Purple
    "+compost" = rgb(220, 180, 60, maxColorValue = 255),       # Bright Golden Yellow
    "wet" = rgb(0, 0, 255, maxColorValue = 255),
    "dry" = rgb(183, 65, 14, maxColorValue = 255)
  )
)

LS0tCnRpdGxlOiAiT3ZlcmxheSBUcmFpdCBEYXRhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIExpYnJhcmllcwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoaHR0cikgIyByZWFkIG91dCBEcm9wYm94IGZvbGRlcnMKbGlicmFyeSh2ZWdhbikKbGlicmFyeShyZWFkeGwpCmBgYAoKIyMgTWFrZSBzcGVjaWVzIHggdHJhaXQgbWF0cml4CgpHcmVlbmhvdXNlIHRyYWl0cwoKLSAgIGhlaWdodCwgbGVhZiBkcnkgbWF0dGVyIGNvbnRlbnQsIHNwZWNpZmljIGxlYWYgYXJlYSwgcm9vdCBtYXNzIGZyYWN0aW9uLCByZWxhdGl2ZSBncm93dGggcmF0ZSwgY29hcnNlIHJvb3QgZGlhbWV0ZXIsIHJvb3QgZGVuc2l0eSwgc3BlY2lmaWMgcm9vdCBsZW5ndGggb2YgZmluZSByb290cywgc3BlY2lmaWMgcm9vdCBsZW5ndGggb2YgY29hcnNlIHJvb3RzCgpGaWVsZCB0cmFpdHMKCi0gICBoZWlnaHQsIGxlYWYgZHJ5IG1hdHRlciBjb250ZW50LCBzcGVjaWZpYyBsZWFmIGFyZWEsIHNlZWQgbWFzcywgbGVhZiBDLCBsZWFmIE4KClsiSDE6XXsudW5kZXJsaW5lfSBQYWlyaW5nIGZpZWxkIHJlc3VsdHMgd2l0aCBhIGdyZWVuaG91c2UgMTUgTiBleHBlcmltZW50IHdpbGwgYWxsb3cgdXMgdG8gcmVsYXRlIHNwZWNpZXMgcmVzcG9uc2VzIHRvIHRoZWlyIGFiaWxpdHkgdG8gdXB0YWtlIG9yZ2FuaWMgTiIKCiJJbiBhZGRpdGlvbiwgd2Ugd2lsbCBjb25kdWN0IGEgZ3JlZW5ob3VzZSBleHBlcmltZW50IHRvIGlzb2xhdGUgdGhlIG1lY2hhbmlzbSAobWluZXJhbGl6ZWQgTiB2cyBvcmdhbmljIE4gdXB0YWtlIHJhdGVzICkgYnkgd2hpY2ggY29tcG9zdCBtYXkgYWZmZWN0IHNwZWNpZXMgY29tcG9zaXRpb24iCgpXb3JrZmxvdyBwbGFuOgoKLSAgIG92ZXJsYXkgc3BlY2llcyB0cmFpdCBkYXRhIGFzIHZlY3RvcnMgb24gdGhlIE5NRFMKCiAgICAtICAgb25seSBncmVlbmhvdXNlIHRyYWl0cyBhdmFpbGFibGUgKG9ubHkgc2xhIGRhdGEgZnJvbSBmaWVsZCkKCiAgICAgICAgLSAgIHVzZSBQQyBzY29yZXMgYXMgY29tcG9zaXRlIHRyYWl0IGF4ZXMgT1IKCiAgICAgICAgLSAgIGF2ZXJhZ2UgdGhlIHRyYWl0cyBmb3IgZWFjaCBzcGVjaWVzCgojIyBSZWFkIGluIGFuZCBvdXQgbWF0cmljZXMgZnJvbSB0cmFpdE9yZGluYXRpb24gY29kZQoKYGBge3J9CiMgd3JpdGUuY3N2KG1hdHJpeC5icmF5LCAiZGF0YS9zaXRlYnlzcGVjaWVzX21hdHJpY2VzL2FsbF95ZWFyc19ncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheS5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQptYXRyaXguYnJheSA8LSByZWFkLmNzdigiZGF0YS9zaXRlYnlzcGVjaWVzX21hdHJpY2VzL2FsbF95ZWFyc19ncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheS5jc3YiLCByb3cubmFtZXMgPSAxKQoKIyB3cml0ZS5jc3YobWF0cml4LmJsb2NrLmJyYXksICJkYXRhL3NpdGVieXNwZWNpZXNfbWF0cmljZXMvYWxsX3llYXJzX2dyYXppbmdfc2l0ZWJ5c3BlY2llc19icmF5X2Jsb2NrLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCm1hdHJpeC5ibG9jay5icmF5IDwtIHJlYWQuY3N2KCJkYXRhL3NpdGVieXNwZWNpZXNfbWF0cmljZXMvYWxsX3llYXJzX2dyYXppbmdfc2l0ZWJ5c3BlY2llc19icmF5X2Jsb2NrLmNzdiIsIHJvdy5uYW1lcyA9IDEpCgoKIyB3cml0ZS5jc3YobWF0cml4LmJyYXkubG93LCAiZGF0YS9zaXRlYnlzcGVjaWVzX21hdHJpY2VzL2FsbF95ZWFyc19MT1dncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheS5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQptYXRyaXguYnJheS5sb3cgPC0gcmVhZC5jc3YoImRhdGEvc2l0ZWJ5c3BlY2llc19tYXRyaWNlcy9hbGxfeWVhcnNfTE9XZ3JhemluZ19zaXRlYnlzcGVjaWVzX2JyYXkuY3N2Iiwgcm93Lm5hbWVzID0gMSkKCiMgd3JpdGUuY3N2KG1hdHJpeC5icmF5LjIwMjEsICJkYXRhL3NpdGVieXNwZWNpZXNfbWF0cmljZXMvMjAyMV9ncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheS5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQptYXRyaXguYnJheS4yMDIxIDwtIHJlYWQuY3N2KCJkYXRhL3NpdGVieXNwZWNpZXNfbWF0cmljZXMvMjAyMV9ncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheS5jc3YiLCByb3cubmFtZXMgPSAxKQoKIyB3cml0ZS5jc3YobWF0cml4LmJyYXkuYmxvY2suMjAyMSwgImRhdGEvc2l0ZWJ5c3BlY2llc19tYXRyaWNlcy8yMDIxX2dyYXppbmdfc2l0ZWJ5c3BlY2llc19icmF5X2Jsb2NrLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCm1hdHJpeC5icmF5LmJsb2NrLjIwMjEgPC0gcmVhZC5jc3YoImRhdGEvc2l0ZWJ5c3BlY2llc19tYXRyaWNlcy8yMDIxX2dyYXppbmdfc2l0ZWJ5c3BlY2llc19icmF5X2Jsb2NrLmNzdiIsIHJvdy5uYW1lcyA9IDEpCgojIHdyaXRlLmNzdihtYXRyaXguYnJheS5ibG9jay4yMDIxLmxvdywgImRhdGEvc2l0ZWJ5c3BlY2llc19tYXRyaWNlcy8yMDIxX0xPV2dyYXppbmdfc2l0ZWJ5c3BlY2llc19icmF5X2Jsb2NrLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCm1hdHJpeC5icmF5LmJsb2NrLjIwMjEubG93IDwtIHJlYWQuY3N2KCJkYXRhL3NpdGVieXNwZWNpZXNfbWF0cmljZXMvMjAyMV9MT1dncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheV9ibG9jay5jc3YiLCByb3cubmFtZXMgPSAxKQoKIyB3cml0ZS5jc3YobWF0cml4LmJyYXkuYmxvY2suMjAyMS5oaWdoLCAiZGF0YS9zaXRlYnlzcGVjaWVzX21hdHJpY2VzLzIwMjFfSElHSGdyYXppbmdfc2l0ZWJ5c3BlY2llc19icmF5X2Jsb2NrLmNzdiIsIHJvdy5uYW1lcyA9IFRSVUUpCm1hdHJpeC5icmF5LmJsb2NrLjIwMjEuaGlnaCA8LSByZWFkLmNzdigiZGF0YS9zaXRlYnlzcGVjaWVzX21hdHJpY2VzLzIwMjFfSElHSGdyYXppbmdfc2l0ZWJ5c3BlY2llc19icmF5X2Jsb2NrLmNzdiIsIHJvdy5uYW1lcyA9IDEpCgojIHdyaXRlLmNzdihtYXRyaXguYnJheS4yMDE5LCAiZGF0YS9zaXRlYnlzcGVjaWVzX21hdHJpY2VzLzIwMTlfZ3JhemluZ19zaXRlYnlzcGVjaWVzX2JyYXkuY3N2Iiwgcm93Lm5hbWVzID0gVFJVRSkKbWF0cml4LmJyYXkuMjAxOSA8LSByZWFkLmNzdigiZGF0YS9zaXRlYnlzcGVjaWVzX21hdHJpY2VzLzIwMTlfZ3JhemluZ19zaXRlYnlzcGVjaWVzX2JyYXkuY3N2Iiwgcm93Lm5hbWVzID0gMSkKCiMgd3JpdGUuY3N2KG1hdHJpeC5icmF5LjIwMjAsICJkYXRhL3NpdGVieXNwZWNpZXNfbWF0cmljZXMvMjAyMF9ncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheS5jc3YiLCByb3cubmFtZXMgPSBUUlVFKQptYXRyaXguYnJheS4yMDIwIDwtIHJlYWQuY3N2KCJkYXRhL3NpdGVieXNwZWNpZXNfbWF0cmljZXMvMjAyMF9ncmF6aW5nX3NpdGVieXNwZWNpZXNfYnJheS5jc3YiLCByb3cubmFtZXMgPSAxKQpgYGAKCiMjIyBSZWFkIGluIHRyYWl0IGRhdGEKCmBgYHtyfQojICMgcmVhZCBpbiBncmVlbmhvdXNlIHRyYWl0IGRhdGEKIyB0cmFpdHMuZ2ggPC0gcmVhZC5jc3YoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3NjbC9maS9jOHZrMzFhODA3eGc0OGplejFqMDMvR3JlZW5ob3VzZVRyYWl0cy5jc3Y/cmxrZXk9Y2E3MzZlYTI3azc5bW83aDhkYm42N3FpcSZzdD15YTFjazZwNyZkbD0xIikKIyAKIyAjIHJlYWQgaW4gZmllbGQgdHJhaXQgZGF0YQojICMgZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vc2NsL2ZpL3RycXJuejU0ZGtqb2E5ZG80dGxlNS9sZWFmLWFyZWEtZGF0YV9ORy54bHN4P3Jsa2V5PXMwa2ljMmE1eXFrbmlrYzRpY2VrOHk3cm4mc3Q9ZGw0eDYzNGgmZGw9MSIsZGVzdGZpbGUgPSAiZmllbGRfc2xhLnhsc3giKQojIHRyYWl0cy5zbGEuZmllbGQgPC0gCiMgICByZWFkX2V4Y2VsKCJmaWVsZF9zbGEueGxzeCIsY29sX25hbWVzID0gVFJVRSxjb2xfdHlwZXMgPSAidGV4dCIpCiMgCiMgcmRhKHRyYWl0cy5naCwgc2NhbGUgPSBUUlVFKQpgYGAKCiMjIyMgSW52ZXN0aWdhdGUgdHJhaXQgZGF0YSwgbG9va2luZyBpbiBHcmVlbmhvdXNlIHRyYWl0IGZvbGRlcgoKVHJhaXQgZGF0YSBpcyBpZGVudGljYWwuIFdpbGwgY2xlYW4gZGF0YSBpbgoKYGBge3J9CiMgZHJvcGJveC5tYWluIDwtIHJlYWQuY3N2KCJodHRwczovL3d3dy5kcm9wYm94LmNvbS9zY2wvZmkvYzh2azMxYTgwN3hnNDhqZXoxajAzL0dyZWVuaG91c2VUcmFpdHMuY3N2P3Jsa2V5PWNhNzM2ZWEyN2s3OW1vN2g4ZGJuNjdxaXEmc3Q9MGgxYnM1M2omZGw9MSIpCiMgCiMgZHJvcGJveC5naCA8LSByZWFkLmNzdigiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vc2NsL2ZpLzY3YWF1YmR5ZGl5NGl4ZmZtd3ZmZS9HcmVlbmhvdXNlVHJhaXRzLmNzdj9ybGtleT1ybTJlcWVxb21lN2hnb2VkaG5hbDBneDZkJnN0PXZreW02ZXZ4JmRsPTEiKQojIAojIGFsbC5lcXVhbChkcm9wYm94Lm1haW4sIGRyb3Bib3guZ2gpCiMgaWRlbnRpY2FsKGRyb3Bib3gubWFpbiwgZHJvcGJveC5naCkKYGBgCgpgYGB7cn0KdHJhaXRzLmNsZWFuZWQgPC0gcmVhZC5jc3YoImRhdGEvR3JlZW5ob3VzZVRyYWl0c19jb3JyZWN0ZWRfMjAyNDAyMTIuY3N2IikgJT4lCiAgbXV0YXRlKAogICAgRnJlc2gubGVhZi5tYXNzLi5nLiA9IGFzLm51bWVyaWMoaWZlbHNlKAogICAgICBGcmVzaC5sZWFmLm1hc3MuLmcuID09ICJTa2lwcGVkIGFjY2lkZW50YWxseSIsIE5BLCBGcmVzaC5sZWFmLm1hc3MuLmcuCiAgICApKSwKICAgIERyeS5sZWFmLm1hc3MuLmcuID0gYXMubnVtZXJpYyhpZmVsc2UoCiAgICAgIERyeS5sZWFmLm1hc3MuLmcuID09ICJObyBzYW1wbGUiLCBOQSwgRHJ5LmxlYWYubWFzcy4uZy4KICAgICkpLAogICAgUm9vdC5kcnkuYmlvbWFzcy4uZy4gPSBhcy5udW1lcmljKGlmZWxzZSgKICAgICAgUm9vdC5kcnkuYmlvbWFzcy4uZy4gPT0gInJvb3RzIGxvc3QiLCBOQSwgUm9vdC5kcnkuYmlvbWFzcy4uZy4KICAgICkpLAogICAgUm9vdC52b2x1bWUuLmNtMy4gPSBhcy5udW1lcmljKGlmZWxzZSgKICAgICAgUm9vdC52b2x1bWUuLmNtMy4gPT0gIm5vdCBzY2FubmVkIiwgTkEsIFJvb3Qudm9sdW1lLi5jbTMuCiAgICApKQogICkgCmBgYAoKIyMjIFN1bW1hcml6ZSB0cmFpdCBkYXRhIChHSCkgZm9yIGVhY2ggc3BlY2llcwoKIyMjIyBtZWFucwoKYGBge3J9CiMgbWFrZSB0cmFpdCBzcGVjaWVzIElEIG1hdGNoIG1hdHJpeCBkYXRhIChub3RlcyBzaG93biBiZWxvdykgLS0tLS0tLQp0cmFpdHMuY2xlYW5lZCA8LSB0cmFpdHMuY2xlYW5lZCAlPiUKICBtdXRhdGUoCiAgICBJRCA9IGlmZWxzZSgKICAgICAgSUQgPT0gIkFnb3NlcmlzIiwgIkFHU1AiLCBpZmVsc2UoCiAgICAgICAgSUQgPT0gIkFWRUJBUiIsICJBVkJBIiwgaWZlbHNlKAogICAgICAgICAgSUQgPT0gIkJSRFIiLCAiQlJESSIsIElECiAgICAgICAgKQogICAgICApCiAgICApCiAgKQoKIyBzdW1tYXJ5KHRyYWl0cy5jbGVhbmVkKQp0cmFpdHMubWVhbnMgPC0gdHJhaXRzLmNsZWFuZWQgJT4lCiAgZ3JvdXBfYnkoSUQpICU+JQogIHN1bW1hcmlzZSgKICAgIGFjcm9zcyg0OihuY29sKHRyYWl0cy5naCkgLSAxKSwgbGlzdChtZWFuID0gfm1lYW4oLngsIG5hLnJtID0gVFJVRSkKICApKSkgJT4lCiAgcmVuYW1lKAogICAgSGVpZ2h0ID0gSGVpZ2h0Li5jbS5fbWVhbiwKICAgIEZyZXNoTGVhZk1hc3MgPSBGcmVzaC5sZWFmLm1hc3MuLmcuX21lYW4sCiAgICBEcnlMZWFmTWFzcyA9IERyeS5sZWFmLm1hc3MuLmcuX21lYW4sCiAgICBMRE1DID0gTERNQ19tZWFuLCAjIExlYWYgZHJ5IG1hdHRlciBjb250ZW50IChMRE1DLCB0aGUgcmF0aW8gb2YgbGVhZiBkcnkgbWFzcyB0byBmcmVzaCBtYXNzKQogICAgTGVhZkFyZWEgPSBMZWFmLkFyZWEuLmNtMi5fbWVhbiwKICAgIFNMQSA9IFNMQS4uY20yLmcuX21lYW4sCiAgICBTaG9vdERyeUJpb21hc3MgPSBTaG9vdC5kcnkuYmlvbWFzcy4uZy5fbWVhbiwKICAgIFJvb3REcnlCaW9tYXNzID0gUm9vdC5kcnkuYmlvbWFzcy4uZy5fbWVhbiwKICAgIFRvdGFsQmlvbWFzcyA9IFRvdGFsLmJpb21hc3MuLmcuX21lYW4sCiAgICBSTUYgPSBSTUZfbWVhbiwgIyBSb290IG1hc3MgZnJhY3Rpb24gKFJNRikgaXMgYSBwbGFudCB0cmFpdCB0aGF0IG1lYXN1cmVzIHRoZSBwcm9wb3J0aW9uIG9mIGEgcGxhbnQncyBkcnkgbWFzcyB0aGF0IGlzIGluIGl0cyByb290cwogICAgUm9vdFZvbCA9IFJvb3Qudm9sdW1lLi5jbTMuX21lYW4sCiAgICBSb290RGVuc2l0eSA9IFJvb3QuZGVuc2l0eS4uZy5jbTMuX21lYW4sCiAgICBDb2Fyc2VSb290RGlhbWV0ZXIgPSBDb2Fyc2Uucm9vdC5kaWFtZXRlci4ubW0uX21lYW4sCiAgICBSb290TGVuZ3RoID0gTGVuZ3RoLi5tbS5fbWVhbiwKICAgIEZpbmVSb290TGVuZ3RoID0gRmluZS5yb290Lmxlbmd0aC4ubW0uX21lYW4sCiAgICBDb2Fyc2VSb290TGVuZ3RoID0gQ29hcnNlLnJvb3QubGVuZ3RoLi5tbS5fbWVhbiwKICAgIENvYXJzZVJvb3RTcGVjTGVuZ3RoID0gQ29hcnNlLnJvb3Quc3BlY2lmaWMubGVuZ3RoLi5jbS5nLl9tZWFuLAogICAgRmluZVJvb3RTcGVjTGVuZ3RoID0gRmluZS5yb290LnNwZWNpZmljLmxlbmd0aC4uY20uZy5fbWVhbiwKICAgIFByb3BGaW5lUm9vdHMgPSBQcm9wb3J0aW9uLmZpbmUucm9vdHNfbWVhbgogICkKICAKCiMgbWFrZSBzaXRlIGJ5IHNwZWNpZXMgbWF0cml4IG1hdGNoIHRyYWl0cyBzcGVjaWVzCm1hdHJpeC5uYW1lcyA8LSBkYXRhLmZyYW1lKGNvbG5hbWVzKG1hdHJpeC5icmF5KSkgI3NwZWNpZXMgY29tcCAoNzUgY291bnQpCnRyYWl0Lm5hbWVzIDwtIGRhdGEuZnJhbWUodHJhaXRzLm1lYW5zJElEKSAjdHJhaXQgc3BlY2llcyAoODAgY291bnQpCgppbnRlcnNlY3QubmFtZXMgPC0gaW50ZXJzZWN0KGNvbG5hbWVzKG1hdHJpeC5icmF5KSwgdHJhaXRzLm1lYW5zJElEKSAjIHNhbWUgc3BlY2llcyAoNDMgY291bnQpCnNldGRpZmYoY29sbmFtZXMobWF0cml4LmJyYXkpLCB0cmFpdHMubWVhbnMkSUQpCnNldGRpZmYodHJhaXRzLm1lYW5zJElELCBjb2xuYW1lcyhtYXRyaXguYnJheSkpCgojIGNoZWNrIG1hdHJpeCBjb2RlcyB0byBzZWUgaWYgc2FtZSBzcGVjaWVzIGFyZSBuYW1lZCBkaWZmZXJlbnQgdGhpbmdzCnVuaXF1ZS5tYXRyaXguc3BlY2llcyA8LSBjb3Zlci5kYXQgJT4lCiAgZHBseXI6OnNlbGVjdChjb2RlNCwgc3BlY2llcykgJT4lCiAgc3VtbWFyaXNlKAogICAgY29kZTQgPSB1bmlxdWUoY29kZTQpLAogICAgc3BlY2llcyA9IHVuaXF1ZShzcGVjaWVzKQogICkKCnVuaXF1ZS50cmFpdC5zcGVjaWVzIDwtIHRyYWl0cy5jbGVhbmVkICU+JQogIGRwbHlyOjpzZWxlY3QoVGF4b24sIElEKSAlPiUKICBkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVFJVRSkKICAKCiMgd3JpdGUgdHJhaXRzLm1lYW5zIGNzdiAtLS0tCiMgd3JpdGUuY3N2KHRyYWl0cy5tZWFucywgImRhdGEvdHJhaXRzL2FsbF9zcF90cmFpdF9tZWFucy5jc3YiKQogCgojIHdyaXRlLmNzdih0cmFpdHMubWVhbnMuY29tcCwgImRhdGEvdHJhaXRzL2ZpZWxkX3NwX3RyYWl0X21lYW5zLmNzdiIpCmBgYAoKIyMjIDwhLS0jICAtLT5TZWUgaWYgSSBoYXZlIHRvIG1hdGNoIG5hbWVzIHdpdGggdHJhaXRzIGV2ZXIgeWVhciAoQU5TOiBBbGwgU2FtZSBTcGVjaWVzKQoKYGBge3J9CiMgIyBhbGwgeWVhcnMgLS0tLS0tLS0tLS0tLQojICMgbWFrZSBzaXRlIGJ5IHNwZWNpZXMgbWF0cml4IG1hdGNoIHRyYWl0cyBzcGVjaWVzCiMgbWF0cml4Lm5hbWVzIDwtIGRhdGEuZnJhbWUoY29sbmFtZXMobWF0cml4LmJyYXkpKSAjc3BlY2llcyBjb21wICg3NSBjb3VudCkKIyB0cmFpdC5uYW1lcyA8LSBkYXRhLmZyYW1lKHRyYWl0cy5tZWFucyRJRCkgI3RyYWl0IHNwZWNpZXMgKDgwIGNvdW50KQojIAojIGludGVyc2VjdC5uYW1lcyA8LSBpbnRlcnNlY3QoY29sbmFtZXMobWF0cml4LmJyYXkpLCB0cmFpdHMubWVhbnMkSUQpICMgc2FtZSBzcGVjaWVzICg0MyBjb3VudCkKIyBzZXRkaWZmKGNvbG5hbWVzKG1hdHJpeC5icmF5KSwgdHJhaXRzLm1lYW5zJElEKQojIHNldGRpZmYodHJhaXRzLm1lYW5zJElELCBjb2xuYW1lcyhtYXRyaXguYnJheSkpCiMgCiMgIyBjaGVjayBtYXRyaXggY29kZXMgdG8gc2VlIGlmIHNhbWUgc3BlY2llcyBhcmUgbmFtZWQgZGlmZmVyZW50IHRoaW5ncwojIHVuaXF1ZS5tYXRyaXguc3BlY2llcyA8LSBjb3Zlci5kYXQgJT4lCiMgICBkcGx5cjo6c2VsZWN0KGNvZGU0LCBzcGVjaWVzKSAlPiUKIyAgIHN1bW1hcmlzZSgKIyAgICAgY29kZTQgPSB1bmlxdWUoY29kZTQpLAojICAgICBzcGVjaWVzID0gdW5pcXVlKHNwZWNpZXMpCiMgICApCiMgCiMgdW5pcXVlLnRyYWl0LnNwZWNpZXMgPC0gdHJhaXRzLmNsZWFuZWQgJT4lCiMgICBkcGx5cjo6c2VsZWN0KFRheG9uLCBJRCkgJT4lCiMgICBkaXN0aW5jdChJRCwgLmtlZXBfYWxsID0gVFJVRSkKIyAgIAojICMgMjAxOSAtLS0tLS0tLS0tLS0tCiMgZGF0YS5mcmFtZShjb2xuYW1lcyhtYXRyaXguYnJheS4yMDE5KSkgI3NwZWNpZXMgY29tcCAoNzUgY291bnQpCiMgZGF0YS5mcmFtZShjb2xuYW1lcyhtYXRyaXguYnJheS4yMDIwKSkgI3NwZWNpZXMgY29tcCAoNzUgY291bnQpCiMgZGF0YS5mcmFtZShjb2xuYW1lcyhtYXRyaXguYnJheS4yMDIxKSkgI3NwZWNpZXMgY29tcCAoNzUgY291bnQpCmBgYAoKLSAgICoqKmNoYW5nZSoqKiBUcmFpdCBuYW1lOiAnQWdvc2VyaXMnIC0tXD4gJ0Fnb3NlcmlzIHVua25vd24nOyBhc3N1bWluZyB0aGUgc2FtZSBhcyAnQUdTUCcgLS1cPiAnQWdvc2VyaXMgc3AuJyBpbiBtYXRyaXggZGF0YSAoY2hhbmdlIHRvIG1hdHJpeCBuYW1lKQoKLSAgIFtXaGF0J3MgdGhlIGRpZmZlcmVuY2UgYmV0d2Vlbjpdey51bmRlcmxpbmV9CgogICAgLSAgICdBTkFSJyBhbmQgJ0FOQVJwJyBpbiB0cmFpdCBkYXRhPwoKICAgIC0gICAnQlJITycgYW5kICdCUkhPcCcgaW4gdHJhaXQgZGF0YT8KCiAgICAtICAgJ0JSTklmJyBhbmQgJ0JSTklwJyBpbiB0cmFpdCBkYXRhPyAobm90IGluIG1hdHJpeCBkYXRhKQoKICAgIC0gICAnQ0xQVWYnIGFuZCAnQ0xQVXAnIGluIHRyYWl0IGRhdGE/IChub3QgaW4gbWF0cml4IGRhdGEpCgogICAgLSAgICdHSVRSZicgYW5kICdHSVRScCcgaW4gdHJhaXQgZGF0YT8gKG5vdCBpbiBtYXRyaXggZGF0YSkKCiAgICAtICAgJ0xFTklmJyBhbmQgJ0xFTklwJyBpbiB0cmFpdCBkYXRhPyAobm90IGluIG1hdHJpeCBkYXRhKQoKICAgIC0gICAnVFJISScgYW5kICdUUkhJcGknIChzYW1lIHNwIG5hbWUpIGluIHRyYWl0IGRhdGE/IChUUkhJIGluIG1hdHJpeCBkYXRhKQoKICAgIC0gICAnVFJXSWYnIGFuZCAnVFJXSXAnIGFuZCAnVFJXSXBpJyBpbiB0cmFpdCBkYXRhPyAobm90IGluIG1hdHJpeCBkYXRhKQoKICAgIC0gICAnQ3Jhc3N1bGEnIGFuZCAnQ3Jhc3N1bGEgdGlsbGFlYScgKGNvdWxkIHRoZXkgYmUgdGhlIHNhbWU/KQoKICAgIC0gICAnU2FuaWN1bGEnICh1bmtub3duKSBhbmQgJ1NBQkkxJyBvciAnU0FCSTInIChjb3VsZCB0aGV5IGJlIHRoZSBzYW1lPykKCiAgICAtICAgJ01BRUxmJyAodHJhaXQgZGF0YSkgYW5kICdNQUQxJyAoTWFkaWEgc3AuIDEgKCJ0YWxsIHRhcndlZWQiKScgKGNvdWxkIHRoZXkgYmUgdGhlIHNhbWU/KQoKICAgIC0gICAnTUFFTHAnICh0cmFpdCBkYXRhKSBhbmQgJ01BRDInIChNYWRpYSBzcC4gMSAoInNtYWxsIHRhcndlZWQiKScgKGNvdWxkIHRoZXkgYmUgdGhlIHNhbWU/KQoKICAgIC0gICAnVHJpZm9saXVtIGVyaW9jZXBoYWx1bScgKFRSRVIpIGFuZCAnVHJpcGh5c2FyaWEgZXJpYW50aGEnIChUUkVSKSAoY291bGQgdGhleSBiZSB0aGUgc2FtZT8pCgotICAgKioqY2hhbmdlKioqICdBVkVCQVInICh0cmFpdCBkYXRhKSB0byAnQVZCQScgKG1hdHJpeCBkYXRhKQoKLSAgICoqKmNoYW5nZSoqKiBCUkRSIC0tXD4gQlJESQoKIyMgT3ZlcmxheSBUcmFpdCBWZWN0b3JzIG9udG8gTk1EUwoKWyoqQWJvdmVncm91bmQgVHJhaXRzKipdey51bmRlcmxpbmV9CgotICAgSGVpZ2h0CgotICAgKipMZWFmKioKCiAgICAtICAgRnJlc2hMZWFmTWFzcwoKICAgIC0gICBEcnlMZWFmTWFzcwoKICAgIC0gICBMRE1DCgogICAgICAgIC0gICBMZWFmIGRyeSBtYXR0ZXIgY29udGVudCAoTERNQywgdGhlIHJhdGlvIG9mIGxlYWYgZHJ5IG1hc3MgdG8gZnJlc2ggbWFzcykKCiAgICAtICAgTGVhZkFyZWEKCiAgICAtICAgU0xBCgogICAgLSAgIFNob290RHJ5QmlvbWFzcwoKWyoqQmVsb3dncm91bmQgVHJhaXRzKipdey51bmRlcmxpbmV9CgotICAgUm9vdERyeUJpb21hc3MKCi0gICBSTUYKCiAgICAtICAgUm9vdCBtYXNzIGZyYWN0aW9uIChSTUYpIGlzIGEgcGxhbnQgdHJhaXQgdGhhdCBtZWFzdXJlcyB0aGUgcHJvcG9ydGlvbiBvZiBhIHBsYW50J3MgZHJ5IG1hc3MgdGhhdCBpcyBpbiBpdHMgcm9vdHMKCi0gICBSb290Vm9sCgotICAgUm9vdERlbnNpdHkKCi0gICBSb290TGVuZ3RoCgotICAgUHJvcEZpbmVSb290cwoKLSAgICoqQ29hcnNlIFJvb3RzKioKCiAgICAtICAgQ29hcnNlUm9vdERpYW1ldGVyCgogICAgLSAgIENvYXJzZVJvb3RMZW5ndGgKCiAgICAtICAgQ29hcnNlUm9vdFNwZWNMZW5ndGgKCi0gICAqKkZpbmUgUm9vdHMqKgoKICAgIC0gICBGaW5lUm9vdExlbmd0aAoKICAgIC0gICBGaW5lUm9vdFNwZWNMZW5ndGgKCi0gICBUb3RhbEJpb21hc3MKCiMjIyBBTEwgWUVBUlMgLS0gTE9XIEFORCBISUdIIEdSQVpJTkcKCiMjIyMgUHJlcGFyZSBOTURTIGFuZCBUcmFpdHMKClN0cmVzczoKCmBgYCAgICAgICAgIAowLjIwMTExMjcKYGBgCgpgYGB7cn0KIyBzdWJzZXQgbm1kcyB0byBtYXRjaCBzcGVjaWVzIG5hbWVzCm5tZHMuY29tcC50cmFpdCA8LSBtZXRhTURTKG1hdHJpeC5icmF5ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoaW50ZXJzZWN0Lm5hbWVzKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuY29tcC50cmFpdCAjIHByZXR0eSBub3QgZ3JlYXQgc3RyZXNzCnN0cmVzc3Bsb3Qobm1kcy5jb21wLnRyYWl0KQpwbG90KG5tZHMuY29tcC50cmFpdCwgdHlwZT0idCIpCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLmNvbXAudHJhaXQsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKbm1kczIgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy5jb21wLnRyYWl0LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzX2RhdF90cmFpdCA8LSBjYmluZChubWRzMSwgbm1kczIpICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgICMgRW5zdXJlIGl0J3MgYSBkYXRhIGZyYW1lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJzaXRlX2lkIikgJT4lICAjIE1vdmUgcm93IG5hbWVzIGludG8gYSBuZXcgY29sdW1uCiAgc2VwYXJhdGUoc2l0ZV9pZCwgaW50byA9IGMoIm51dF90cnQiLCAicHB0X3RydCIsICJ5ciIsICJncmF6aW5nX2hpc3QiKSwgc2VwID0gIl8iKQoKCiMgc3Vic2V0IG1hdHJpeCBhbmQgdHJhaXQgZGF0YSB0byBtYXRjaCBuYW1lcwp0cmFpdHMubWVhbnMuY29tcCA8LSB0cmFpdHMubWVhbnMgJT4lCiAgZmlsdGVyKElEICVpbiUgaW50ZXJzZWN0Lm5hbWVzKSAKCiMgdHJhaXRzLm1lYW5zLmNvbXAyIDwtIHRyYWl0cy5tZWFucy5jb21wICU+JQojIGRwbHlyOjpzZWxlY3QoLUlEKQpyb3duYW1lcyh0cmFpdHMubWVhbnMuY29tcDIpIDwtIHRyYWl0cy5tZWFucy5jb21wJElECgojIHRyYWl0IHZlY3RvcnMgb250byB0aGUgTk1EUwojIGVudmZpdChubWRzLmNvbXAudHJhaXQsIHRyYWl0cy5tZWFucy5jb21wLCBwZXJtdXRhdGlvbnMgPSA5OTkpCiMgZXhhbXBsZSBmcm9tIHN0YWNrIG92ZXJmbG93OiBlbnZmaXQob3JkIH4gdmFyMSArIHZhcjIgKyB2YXIzLCBkdW5lLnNwZWMsIGRpc3BsYXk9InNwIiksICdvcmQnIGlzIHRoZSBubWRzIG1vZGVsLCAndmFyMScgaXMgdGhlIHRyYWl0MSBpIHRoaW5rPwoKY29sbmFtZXModHJhaXRzLm1lYW5zLmNvbXApCnZlY3RvcnMubm1kcy5jb21wLnRyYWl0IDwtIGVudmZpdChubWRzLmNvbXAudHJhaXQgfiBIZWlnaHQgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTGVhZkFyZWEgKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBSTUYsIHRyYWl0cy5tZWFucy5jb21wLCBkaXNwbGF5ID0gInNwIikgIyBPTkxZIEhlaWdodCwgTGVhZiBhcmVhLCBhbmQgUk1GIHNpZ25pZmljYW50CgojVEVNUExBVEU6IAogICMgZW52Zml0KG5tZHMuYmxvY2sudHJhaXQgfiBIZWlnaHQgKyAKICAjICAgICAgICAgIEZyZXNoTGVhZk1hc3MgKwogICMgICAgICAgICAgRHJ5TGVhZk1hc3MgKwogICMgICAgICAgICAgTERNQyArCiAgIyAgICAgICAgICBMZWFmQXJlYSArCiAgIyAgICAgICAgICBTTEEgKwogICMgICAgICAgICAgU2hvb3REcnlCaW9tYXNzICsKICAjICAgICAgICAgIFJvb3REcnlCaW9tYXNzICsKICAjICAgICAgICAgIFRvdGFsQmlvbWFzcyArCiAgIyAgICAgICAgICBSTUYgKwogICMgICAgICAgICAgUm9vdFZvbCArCiAgIyAgICAgICAgICBSb290RGVuc2l0eSArCiAgIyAgICAgICAgICBDb2Fyc2VSb290RGlhbWV0ZXIgKwogICMgICAgICAgICAgUm9vdExlbmd0aCArCiAgIyAgICAgICAgICBGaW5lUm9vdExlbmd0aCArCiAgIyAgICAgICAgICBDb2Fyc2VSb290TGVuZ3RoICsKICAjICAgICAgICAgIENvYXJzZVJvb3RTcGVjTGVuZ3RoICsKICAjICAgICAgICAgIEZpbmVSb290U3BlY0xlbmd0aCArCiAgIyAgICAgICAgICBQcm9wRmluZVJvb3RzLCB0cmFpdHMubWVhbnMuY29tcCwgZGlzcGxheSA9ICJzcCIsIG5hLnJtID0gVFJVRSkKCiMgaXMgaXQgZGlmZmVyZW50IHdoZW4geW91IG9ubHkgZG8gY2VydGFpbiB0cmFpdHMgKGFib3ZlLSB2cy4gYmVsb3ctZ3JvdW5kKT8gb3IgY2FuIHlvdSBqdXN0IHRocm93IGV2ZXJ5dGhpbmcgaW4gdGhlcmUgYW5kIGl0IHdpbGwgdGVsbCB5b3Ugd2hhdCBpcyBzaWduaWZpY2FudCBhbmQgeW91IGNhbiBzdWJzZXQgZnJvbSB0aGVyZT8KCiMgTG9va3MgbGlrZSBkaWZmZXJlbnQgc3Vic2V0cyBvZiB0cmFpdHMgcHV0IGluIGFyZSB0aGUgc2FtZSwgc28gSSBzaGFsbCBwcm9jZWVkIHdpdGggdGhlIG1lZ2EgbW9kZWxzIGFuZCB2ZXJpZnkgd2l0aCBMYXVyZW4KCnRyYWl0X3ZlY3RvcnMgPC0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cykKCmBgYAoKTk1EUyBtb2RlbDogb25seSBIZWlnaHQsIExlYWYgYXJlYSwgYW5kIFJNRiAoKSBmb3VuZCBzaWduaWZpY2FudC4KCiMjIyMgUGxvdAoKYGBge3J9CmdncGxvdChubWRzX2RhdF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArCiAgY3VzdG9tX2NvbG9ycyArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgdmFsdWVzID0gYygKICAgICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICAgICkKICApICsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cyksIAogICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IE5NRFMxLCB5ZW5kID0gTk1EUzIpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIHNpemUgPSAxCiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLmNvbXAudHJhaXQkdmVjdG9ycyRhcnJvd3MpLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgpnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsIGNvbG9yID0gYXMuZmFjdG9yKHlyKSwgZmlsbCA9IGFzLmZhY3Rvcih5cikpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IFllYXIiKSsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cyksIAogICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IE5NRFMxLCB5ZW5kID0gTk1EUzIpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIHNpemUgPSAxCiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLmNvbXAudHJhaXQkdmVjdG9ycyRhcnJvd3MpLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgpnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsIGZpbGwgPSBhcy5mYWN0b3IocHB0X3RydCksIGNvbG9yID0gYXMuZmFjdG9yKHBwdF90cnQpKSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKwogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpICsKICBjdXN0b21fY29sb3JzICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKSsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cyksIAogICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IE5NRFMxLCB5ZW5kID0gTk1EUzIpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIHNpemUgPSAxCiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLmNvbXAudHJhaXQkdmVjdG9ycyRhcnJvd3MpLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgpnZ3Bsb3Qobm1kc19kYXRfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCkpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEdyYXppbmcgSGlzdG9yeSIpICsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cyksIAogICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IE5NRFMxLCB5ZW5kID0gTk1EUzIpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIHNpemUgPSAxCiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLmNvbXAudHJhaXQkdmVjdG9ycyRhcnJvd3MpLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgojIGdncGxvdChubWRzX2RhdF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGNvbG9yID0gYXMuZmFjdG9yKGdyYXppbmdfaGlzdCksIGZpbGwgPSBhcy5mYWN0b3IoeXIpKSkgKwojICAgZ2VvbV9wb2ludChhZXMoZmlsbCA9IGFzLmZhY3Rvcih5cikpLCBzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMSkgKwojICAgc3RhdF9lbGxpcHNlKGFlcyhjb2xvciA9IGFzLmZhY3Rvcih5cikpLAojICAgICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAojICAgICAgICAgICAgICAgIGZpbGwgPSBOQSwKIyAgICAgICAgICAgICAgICBzaXplID0gMSkgKwojICAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IEdyYXppbmcgSGlzdG9yeSAmIFllYXIiKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwoCiMgICB2YWx1ZXMgPSBjKAojICAgICAibG93IiA9ICJjeWFuIiwKIyAgICAgImhpZ2giID0gImJyb3duIiwKIyAgICIyMDE5IiA9ICJzYWxtb24iLAojICAgIjIwMjAiID0gImxpbWVncmVlbiIsCiMgICAiMjAyMSIgPSAiY29ybmZsb3dlcmJsdWUiKQojICAgKSArCiMgICBnZW9tX3NlZ21lbnQoCiMgICAgIGRhdGEgPSBhcy5kYXRhLmZyYW1lKHZlY3RvcnMubm1kcy5jb21wLnRyYWl0JHZlY3RvcnMkYXJyb3dzKSwgCiMgICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiMgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKIyAgICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLCAKIyAgICAgY29sb3IgPSAicmVkIiwgCiMgICAgIHNpemUgPSAxCiMgICApICsKIyAgIGdlb21fdGV4dCgKIyAgICAgZGF0YSA9IGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLmNvbXAudHJhaXQkdmVjdG9ycyRhcnJvd3MpLCAKIyAgICAgYWVzKHggPSBOTURTMSwgeSA9IE5NRFMyLCBsYWJlbCA9IHJvd25hbWVzKHZlY3RvcnMubm1kcy5jb21wLnRyYWl0JHZlY3RvcnMkYXJyb3dzKSksIAojICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyBBdm9pZHMgdW53YW50ZWQgaW5oZXJpdGFuY2UKIyAgICAgaGp1c3QgPSAtMC4yLCAKIyAgICAgdmp1c3QgPSAtMC4yLCAKIyAgICAgY29sb3IgPSAicmVkIiwKIyAgICAgc2l6ZSA9IDUKIyAgICkKIyAgIAojIGdncGxvdChubWRzX2RhdF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgY29sb3IgPSBudXRfdHJ0LCBmaWxsID0gYXMuZmFjdG9yKHlyKSkpICsKIyAgIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDEpICsKIyAgIHN0YXRfZWxsaXBzZShhZXMoY29sb3IgPSBhcy5mYWN0b3IobnV0X3RydCkpLAojICAgICAgICAgICAgICBnZW9tID0gInBvbHlnb24iLAojICAgICAgICAgICAgICBmaWxsID0gTkEsICAjIE1ha2VzIHRoZSBlbGxpcHNlIHRyYW5zcGFyZW50IGluc2lkZQojICAgICAgICAgICAgICBzaXplID0gMSkgKwojICAgbGFicyh0aXRsZSA9ICJHcm91cGVkIGJ5IE51dHJpZW50IFRyZWF0bWVudCAmIFllYXIiKSArCiMgICBzY2FsZV9jb2xvcl9tYW51YWwoCiMgICB2YWx1ZXMgPSBjKAojICAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKIyAgICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKIyAgICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiMgICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiMgICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQojICAgKQojICkgKwojICAgZ2VvbV9zZWdtZW50KAojICAgICBkYXRhID0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cyksIAojICAgICBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gTk1EUzEsIHllbmQgPSBOTURTMiksIAojICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiMgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiMgICAgIGNvbG9yID0gInJlZCIsIAojICAgICBzaXplID0gMQojICAgKSArCiMgICBnZW9tX3RleHQoCiMgICAgIGRhdGEgPSBhcy5kYXRhLmZyYW1lKHZlY3RvcnMubm1kcy5jb21wLnRyYWl0JHZlY3RvcnMkYXJyb3dzKSwgCiMgICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh2ZWN0b3JzLm5tZHMuY29tcC50cmFpdCR2ZWN0b3JzJGFycm93cykpLCAKIyAgICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMgQXZvaWRzIHVud2FudGVkIGluaGVyaXRhbmNlCiMgICAgIGhqdXN0ID0gLTAuMiwgCiMgICAgIHZqdXN0ID0gLTAuMiwgCiMgICAgIGNvbG9yID0gInJlZCIsCiMgICAgIHNpemUgPSA1CiMgICApCmBgYAoKIyMjIEFMTCBZRUFSUyAtLSBMT1cgQU5EIEhJR0ggR1JBWklORyAoQmxvY2tzKQoKU3RyZXNzOgoKYGBgICAgICAgICAgCjAuMjM1MzkzNwpgYGAKCiMjIyMgUHJlcGFyZSBOTURTIGFuZCBUcmFpdHMKCmBgYHtyfQojIHN1YnNldCBubWRzIHRvIG1hdGNoIHNwZWNpZXMgbmFtZXMKbm1kcy5ibG9jay50cmFpdCA8LSBtZXRhTURTKG1hdHJpeC5ibG9jay5icmF5ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoaW50ZXJzZWN0Lm5hbWVzKSwgLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLmJsb2NrLnRyYWl0ICMgcHJldHR5IG5vdCBncmVhdCBzdHJlc3MKCm5tZHMxIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuYmxvY2sudHJhaXQsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKbm1kczIgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy5ibG9jay50cmFpdCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc19kYXRfYmxvY2tfdHJhaXQgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lICAjIEVuc3VyZSBpdCdzIGEgZGF0YSBmcmFtZQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2l0ZV9pZCIpICU+JSAgIyBNb3ZlIHJvdyBuYW1lcyBpbnRvIGEgbmV3IGNvbHVtbgogIHNlcGFyYXRlKHNpdGVfaWQsIGludG8gPSBjKCJudXRfdHJ0IiwgInBwdF90cnQiLCAieXIiLCAiZ3JhemluZ19oaXN0IiksIHNlcCA9ICJfIikKCgojIHRyYWl0IGRhdGEKdHJhaXRzLm1lYW5zLmNvbXAgCgojIHRyYWl0IHZlY3RvcnMgb250byB0aGUgTk1EUwp2ZWN0b3JzLm5tZHMuYmxvY2sudHJhaXQgPC0KICBlbnZmaXQobm1kcy5ibG9jay50cmFpdCB+IEhlaWdodCArIAogICAgICAgICAgIERyeUxlYWZNYXNzICsKICAgICAgICAgICBMZWFmQXJlYSArCiAgICAgICAgICAgUm9vdERyeUJpb21hc3MgKwogICAgICAgICAgIFJNRiArCiAgICAgICAgICAgUm9vdERlbnNpdHksIHRyYWl0cy5tZWFucy5jb21wLCBkaXNwbGF5ID0gInNwIikKIyBPTkxZIEhlaWdodCwgRHJ5TGVhZk1hc3MsIExlYWZBcmVhLCBSTUYgc2lnbmlmaWNhbnQgKFJvb3REcnlCaW9tYXNzLCBSb290RGVuc2l0eSBtYXJnaW5hbCkKCnRyYWl0X3ZlY3RvcnMgPC0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuYmxvY2sudHJhaXQkdmVjdG9ycyRhcnJvd3MpCgpgYGAKCiMjIyMgUGxvdAoKYGBge3J9CmdncGxvdChubWRzX2RhdF9ibG9ja190cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBOdXRyaWVudCBUcmVhdG1lbnQgLSBCbG9ja3MgdyBUcmFpdHMiKSArCiAgY3VzdG9tX2NvbG9ycyArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikgKwogIGdlb21fc2VnbWVudCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksIAogICAgY29sb3IgPSAicmVkIiwgCiAgICBzaXplID0gMQogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh0cmFpdF92ZWN0b3JzKSksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMgQXZvaWRzIHVud2FudGVkIGluaGVyaXRhbmNlCiAgICBoanVzdCA9IC0wLjIsIAogICAgdmp1c3QgPSAtMC4yLCAKICAgIGNvbG9yID0gInJlZCIsCiAgICBzaXplID0gNQogICkKCmdncGxvdChubWRzX2RhdF9ibG9ja190cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0LCBjb2xvciA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIGxhYnModGl0bGUgPSAiR3JvdXBlZCBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCAtIEJsb2NrcyB3IFRyYWl0cyIpICsKICBjdXN0b21fY29sb3JzICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKSArCiAgZ2VvbV9zZWdtZW50KAogICAgZGF0YSA9IHRyYWl0X3ZlY3RvcnMsIAogICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IE5NRFMxLCB5ZW5kID0gTk1EUzIpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIHNpemUgPSAxCiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IHRyYWl0X3ZlY3RvcnMsIAogICAgYWVzKHggPSBOTURTMSwgeSA9IE5NRFMyLCBsYWJlbCA9IHJvd25hbWVzKHRyYWl0X3ZlY3RvcnMpKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyBBdm9pZHMgdW53YW50ZWQgaW5oZXJpdGFuY2UKICAgIGhqdXN0ID0gLTAuMiwgCiAgICB2anVzdCA9IC0wLjIsIAogICAgY29sb3IgPSAicmVkIiwKICAgIHNpemUgPSA1CiAgKQoKCgoKYGBgCgojIyMgKipBbGwgeWVhcnMgLSBMT1cgR1JBWklORyBPTkxZKioKCiMjIyMgUHJlcGFyZSBOTURTIGFuZCBUcmFpdHMKClN0cmVzczoKCmBgYCAgICAgICAgIAowLjE4Nzk2NzEKYGBgCgpgYGB7cn0KIyBzdWJzZXQgbm1kcyB0byBtYXRjaCBzcGVjaWVzIG5hbWVzCm5tZHMubG93LnRyYWl0IDwtIG1ldGFNRFMobWF0cml4LmJyYXkubG93ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoaW50ZXJzZWN0Lm5hbWVzKSwgLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLmxvdy50cmFpdCAKCm5tZHMxIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMubG93LnRyYWl0LCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMubG93LnRyYWl0LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzX2RhdF9sb3dfdHJhaXQgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lICAjIEVuc3VyZSBpdCdzIGEgZGF0YSBmcmFtZQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2l0ZV9pZCIpICU+JSAgIyBNb3ZlIHJvdyBuYW1lcyBpbnRvIGEgbmV3IGNvbHVtbgogIHNlcGFyYXRlKHNpdGVfaWQsIGludG8gPSBjKCJudXRfdHJ0IiwgInBwdF90cnQiLCAieXIiLCAiZ3JhemluZ19oaXN0IiksIHNlcCA9ICJfIikKCgojIHRyYWl0IGRhdGE6IHRyYWl0cy5tZWFucy5jb21wIAoKIyB0cmFpdCB2ZWN0b3JzIG9udG8gdGhlIE5NRFMKdmVjdG9ycy5ubWRzLmxvdy50cmFpdCA8LQogIGVudmZpdChubWRzLmxvdy50cmFpdCB+IEZyZXNoTGVhZk1hc3MgKwogICAgICAgICAgIFJNRiwgdHJhaXRzLm1lYW5zLmNvbXAsIGRpc3BsYXkgPSAic3AiLCBuYS5ybSA9IFRSVUUpCiMgT05MWSBGcmVzaExlYWZNYXNzIChSTUYgbWFyZ2luYWwpCgp0cmFpdF92ZWN0b3JzIDwtIGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLmxvdy50cmFpdCR2ZWN0b3JzJGFycm93cykKCmBgYAoKIyMjIyBQbG90CgpgYGB7cn0KZ2dwbG90KG5tZHNfZGF0X2xvd190cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGxhYnModGl0bGUgPSAiMjAxOS0yMDIxIChMT1cpIHcgVHJhaXRzIC0gR3JvdXBpbmcgYnkgTnV0cmllbnQgVHJlYXRtZW50IikgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBjdXN0b21fY29sb3JzICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikgKwogIGdlb21fc2VnbWVudCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksIAogICAgY29sb3IgPSAicmVkIiwgCiAgICBzaXplID0gMQogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh0cmFpdF92ZWN0b3JzKSksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMgQXZvaWRzIHVud2FudGVkIGluaGVyaXRhbmNlCiAgICBoanVzdCA9IC0wLjIsIAogICAgdmp1c3QgPSAtMC4yLCAKICAgIGNvbG9yID0gInJlZCIsCiAgICBzaXplID0gNQogICkKCmdncGxvdChubWRzX2RhdF9sb3dfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCwgY29sb3IgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBsYWJzKHRpdGxlID0gIjIwMTktMjAyMSAoTE9XKSB3IFRyYWl0cyAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBjdXN0b21fY29sb3JzICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikgKwogIGdlb21fc2VnbWVudCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksIAogICAgY29sb3IgPSAicmVkIiwgCiAgICBzaXplID0gMQogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh0cmFpdF92ZWN0b3JzKSksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMgQXZvaWRzIHVud2FudGVkIGluaGVyaXRhbmNlCiAgICBoanVzdCA9IC0wLjIsIAogICAgdmp1c3QgPSAtMC4yLCAKICAgIGNvbG9yID0gInJlZCIsCiAgICBzaXplID0gNQogICkKYGBgCgojIyMgMjAxOQoKU3RyZXNzOgoKYGBgICAgICAgICAgCjAuMDYyOTA0MzEKYGBgCgojIyMjIFByZXBhcmUgTk1EUyBhbmQgVHJhaXRzCgpgYGB7cn0KIyBzdWJzZXQgbm1kcyB0byBtYXRjaCBzcGVjaWVzIG5hbWVzCm5tZHMuMjAxOS50cmFpdCA8LSBtZXRhTURTKG1hdHJpeC5icmF5LjIwMTkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChpbnRlcnNlY3QubmFtZXMpLCAsIGs9MiwgdHJ5bWF4ID0gMjUpCm5tZHMuMjAxOS50cmFpdCAKCm5tZHMxIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAxOS50cmFpdCwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKQpubWRzMiA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMTkudHJhaXQsIGNob2ljZXM9YygyKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKCm5tZHNfZGF0XzIwMTlfdHJhaXQgPC0gY2JpbmQobm1kczEsIG5tZHMyKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lICAjIEVuc3VyZSBpdCdzIGEgZGF0YSBmcmFtZQogIHJvd25hbWVzX3RvX2NvbHVtbih2YXIgPSAic2l0ZV9pZCIpICU+JSAgIyBNb3ZlIHJvdyBuYW1lcyBpbnRvIGEgbmV3IGNvbHVtbgogIHNlcGFyYXRlKHNpdGVfaWQsIGludG8gPSBjKCJudXRfdHJ0IiwgInBwdF90cnQiLCAieXIiLCAiZ3JhemluZ19oaXN0IiksIHNlcCA9ICJfIikKCgojIHRyYWl0IGRhdGE6IHRyYWl0cy5tZWFucy5jb21wIAoKCiMgdHJhaXQgdmVjdG9ycyBvbnRvIHRoZSBOTURTCnZlY3RvcnMubm1kcy4yMDE5LnRyYWl0IDwtCiAgZW52Zml0KG5tZHMuMjAxOS50cmFpdCB+IEhlaWdodCArIAogICAgICAgICAgIERyeUxlYWZNYXNzICsKICAgICAgICAgICBMZWFmQXJlYSArCiAgICAgICAgICAgUk1GICsKICAgICAgICAgICBSb290RGVuc2l0eSArCiAgICAgICAgICAgQ29hcnNlUm9vdERpYW1ldGVyLCB0cmFpdHMubWVhbnMuY29tcCwgZGlzcGxheSA9ICJzcCIsIG5hLnJtID0gVFJVRSkKCnZlY3RvcnMubm1kcy4yMDE5LnRyYWl0CiMgT05MWSBIZWlnaHQsIExlYWZBcmVhIChEcnlMZWFmTWFzcywgUk1GLCBSb290RGVuc2l0eSwgQ29hcnNlUm9vdERpYW1ldGVyIG1hcmdpbmFsKQoKdHJhaXRfdmVjdG9ycyA8LSBhcy5kYXRhLmZyYW1lKHZlY3RvcnMubm1kcy4yMDE5LnRyYWl0JHZlY3RvcnMkYXJyb3dzKQpgYGAKCiMjIyMgUGxvdAoKYGBge3J9CmdncGxvdChubWRzX2RhdF8yMDE5X3RyYWl0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IG51dF90cnQsIGNvbG9yID0gbnV0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAxOSB3IFRyYWl0cyAtIEdyb3VwaW5nIGJ5IE51dHJpZW50IFRyZWF0bWVudCIpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikgKwogIGdlb21fc2VnbWVudCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksIAogICAgY29sb3IgPSAicmVkIiwgCiAgICBzaXplID0gMQogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh0cmFpdF92ZWN0b3JzKSksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMgQXZvaWRzIHVud2FudGVkIGluaGVyaXRhbmNlCiAgICBoanVzdCA9IC0wLjIsIAogICAgdmp1c3QgPSAtMC4yLCAKICAgIGNvbG9yID0gInJlZCIsCiAgICBzaXplID0gNQogICkKCmdncGxvdChubWRzX2RhdF8yMDE5X3RyYWl0LCBhZXMoTk1EUzEsIE5NRFMyLCAgZmlsbCA9IHBwdF90cnQsIGNvbG9yID0gcHB0X3RydCkpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMjEsIHNpemUgPSA0LCBzdHJva2UgPSAwLjUpICsgCiAgY3VzdG9tX2NvbG9ycyArIAogIGxhYnModGl0bGUgPSAiMjAxOSB3IFRyYWl0cyAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKSArCiAgZ2VvbV9zZWdtZW50KAogICAgZGF0YSA9IHRyYWl0X3ZlY3RvcnMsIAogICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IE5NRFMxLCB5ZW5kID0gTk1EUzIpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIHNpemUgPSAxCiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IHRyYWl0X3ZlY3RvcnMsIAogICAgYWVzKHggPSBOTURTMSwgeSA9IE5NRFMyLCBsYWJlbCA9IHJvd25hbWVzKHRyYWl0X3ZlY3RvcnMpKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyBBdm9pZHMgdW53YW50ZWQgaW5oZXJpdGFuY2UKICAgIGhqdXN0ID0gLTAuMiwgCiAgICB2anVzdCA9IC0wLjIsIAogICAgY29sb3IgPSAicmVkIiwKICAgIHNpemUgPSA1CiAgKQpgYGAKCiMjIyAyMDIwCgpTdHJlc3M6CgpgYGAgICAgICAgICAKMC4xNTEyODY0CmBgYAoKIyMjIyBQcmVwYXJlIE5NRFMgYW5kIFRyYWl0cwoKYGBge3J9CiMgc3Vic2V0IG5tZHMgdG8gbWF0Y2ggc3BlY2llcyBuYW1lcwpubWRzLjIwMjAudHJhaXQgPC0gbWV0YU1EUyhtYXRyaXguYnJheS4yMDIwICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoaW50ZXJzZWN0Lm5hbWVzKSwgLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjAudHJhaXQgCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjAudHJhaXQsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKbm1kczIgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIwLnRyYWl0LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzX2RhdF8yMDIwX3RyYWl0IDwtIGNiaW5kKG5tZHMxLCBubWRzMikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAgIyBFbnN1cmUgaXQncyBhIGRhdGEgZnJhbWUKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInNpdGVfaWQiKSAlPiUgICMgTW92ZSByb3cgbmFtZXMgaW50byBhIG5ldyBjb2x1bW4KICBzZXBhcmF0ZShzaXRlX2lkLCBpbnRvID0gYygibnV0X3RydCIsICJwcHRfdHJ0IiwgInlyIiwgImdyYXppbmdfaGlzdCIpLCBzZXAgPSAiXyIpCgoKIyB0cmFpdCBkYXRhOiB0cmFpdHMubWVhbnMuY29tcCAKCgojIHRyYWl0IHZlY3RvcnMgb250byB0aGUgTk1EUwp2ZWN0b3JzLm5tZHMuMjAyMC50cmFpdCA8LQogIGVudmZpdChubWRzLjIwMjAudHJhaXQgfiBGcmVzaExlYWZNYXNzICsKICAgICAgICAgICBMZWFmQXJlYSwgdHJhaXRzLm1lYW5zLmNvbXAsIGRpc3BsYXkgPSAic3AiLCBuYS5ybSA9IFRSVUUpCgojIE9OTFkgRnJlc2hMZWFmTWFzcywgTGVhZkFyZWEKCnRyYWl0X3ZlY3RvcnMgPC0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuMjAyMC50cmFpdCR2ZWN0b3JzJGFycm93cykKYGBgCgojIyMjIFBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19kYXRfMjAyMF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjAgdyBUcmFpdHMgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopICsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gTk1EUzEsIHllbmQgPSBOTURTMiksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMg8J+agCBQcmV2ZW50cyBpdCBmcm9tIGxvb2tpbmcgZm9yICdudXRfdHJ0JwogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLCAKICAgIGNvbG9yID0gInJlZCIsIAogICAgc2l6ZSA9IDEKICApICsKICBnZW9tX3RleHQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIsIGxhYmVsID0gcm93bmFtZXModHJhaXRfdmVjdG9ycykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgpnZ3Bsb3Qobm1kc19kYXRfMjAyMF90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0LCBjb2xvciA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjAgdyBUcmFpdHMgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikgKwogIGdlb21fc2VnbWVudCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksIAogICAgY29sb3IgPSAicmVkIiwgCiAgICBzaXplID0gMQogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh0cmFpdF92ZWN0b3JzKSksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMgQXZvaWRzIHVud2FudGVkIGluaGVyaXRhbmNlCiAgICBoanVzdCA9IC0wLjIsIAogICAgdmp1c3QgPSAtMC4yLCAKICAgIGNvbG9yID0gInJlZCIsCiAgICBzaXplID0gNQogICkKYGBgCgojIyMgMjAyMQoKIyMjIyBQcmVwYXJlIE5NRFMgYW5kIFRyYWl0cwoKU3RyZXNzOgoKYGBgICAgICAgICAgCjAuMTIzMDYxCmBgYAoKYGBge3J9CiMgc3Vic2V0IG5tZHMgdG8gbWF0Y2ggc3BlY2llcyBuYW1lcwpubWRzLjIwMjEudHJhaXQgPC0gbWV0YU1EUyhtYXRyaXguYnJheS4yMDIxICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoaW50ZXJzZWN0Lm5hbWVzKSwgLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjEudHJhaXQgCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEudHJhaXQsIGNob2ljZXM9YygxKSwgZGlzcGxheT1jKCJzaXRlcyIpKSkKbm1kczIgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLnRyYWl0LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzX2RhdF8yMDIxX3RyYWl0IDwtIGNiaW5kKG5tZHMxLCBubWRzMikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAgIyBFbnN1cmUgaXQncyBhIGRhdGEgZnJhbWUKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInNpdGVfaWQiKSAlPiUgICMgTW92ZSByb3cgbmFtZXMgaW50byBhIG5ldyBjb2x1bW4KICBzZXBhcmF0ZShzaXRlX2lkLCBpbnRvID0gYygibnV0X3RydCIsICJwcHRfdHJ0IiwgInlyIiwgImdyYXppbmdfaGlzdCIpLCBzZXAgPSAiXyIpCgoKIyB0cmFpdCBkYXRhOiB0cmFpdHMubWVhbnMuY29tcCAKcm93bmFtZXModHJhaXRzLm1lYW5zLmNvbXApIDwtIHRyYWl0cy5tZWFucy5jb21wJElECgoKIyB0cmFpdCB2ZWN0b3JzIG9udG8gdGhlIE5NRFMKdmVjdG9ycy5ubWRzLjIwMjEudHJhaXQgPC0KICBlbnZmaXQobm1kcy4yMDIxLnRyYWl0IH4gSGVpZ2h0ICsgCiAgICAgICAgICAgRnJlc2hMZWFmTWFzcyArCiAgICAgICAgICAgTGVhZkFyZWEsIG5hLm9taXQodHJhaXRzLm1lYW5zLmNvbXApLCBkaXNwbGF5ID0gInNwIiwgbmEucm0gPSBUUlVFKQoKIyAoSGVpZ2h0LCBGcmVzaExlYWZNYXNzLCBMZWFmQXJlYSBtYXJnaW5hbCkKCnRyYWl0X3ZlY3RvcnMgPC0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuMjAyMS50cmFpdCR2ZWN0b3JzJGFycm93cykKYGBgCgojIyMjIFBsb3QKCmBgYHtyfQpnZ3Bsb3Qobm1kc19kYXRfMjAyMV90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgdyBUcmFpdHMgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopICsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gTk1EUzEsIHllbmQgPSBOTURTMiksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMg8J+agCBQcmV2ZW50cyBpdCBmcm9tIGxvb2tpbmcgZm9yICdudXRfdHJ0JwogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLCAKICAgIGNvbG9yID0gInJlZCIsIAogICAgc2l6ZSA9IDEKICApICsKICBnZW9tX3RleHQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIsIGxhYmVsID0gcm93bmFtZXModHJhaXRfdmVjdG9ycykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgpnZ3Bsb3Qobm1kc19kYXRfMjAyMV90cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0LCBjb2xvciA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgdyBUcmFpdHMgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpICsgCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikgKwogIGdlb21fc2VnbWVudCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gMCwgeSA9IDAsIHhlbmQgPSBOTURTMSwgeWVuZCA9IE5NRFMyKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyDwn5qAIFByZXZlbnRzIGl0IGZyb20gbG9va2luZyBmb3IgJ251dF90cnQnCiAgICBhcnJvdyA9IGFycm93KGxlbmd0aCA9IHVuaXQoMC4yLCAiY20iKSksIAogICAgY29sb3IgPSAicmVkIiwgCiAgICBzaXplID0gMQogICkgKwogIGdlb21fdGV4dCgKICAgIGRhdGEgPSB0cmFpdF92ZWN0b3JzLCAKICAgIGFlcyh4ID0gTk1EUzEsIHkgPSBOTURTMiwgbGFiZWwgPSByb3duYW1lcyh0cmFpdF92ZWN0b3JzKSksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMgQXZvaWRzIHVud2FudGVkIGluaGVyaXRhbmNlCiAgICBoanVzdCA9IC0wLjIsIAogICAgdmp1c3QgPSAtMC4yLCAKICAgIGNvbG9yID0gInJlZCIsCiAgICBzaXplID0gNQogICkKYGBgCgojIyMgMjAyMSAtLSBCbG9ja3MKClN0cmVzczoKCmBgYCAgICAgICAgIAowLjE3MDc5OQpgYGAKCiMjIyMgUHJlcGFyZSBOTURTIGFuZCBUcmFpdHMKCmBgYHtyfQojIHN1YnNldCBubWRzIHRvIG1hdGNoIHNwZWNpZXMgbmFtZXMKbm1kcy4yMDIxLmJsb2NrLnRyYWl0IDwtIG1ldGFNRFMobWF0cml4LmJyYXkuYmxvY2suMjAyMSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGludGVyc2VjdC5uYW1lcyksICwgaz0yLCB0cnltYXggPSAyNSkKbm1kcy4yMDIxLmJsb2NrLnRyYWl0IAoKbm1kczEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLmJsb2NrLnRyYWl0LCBjaG9pY2VzPWMoMSksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCm5tZHMyIDwtIGFzLmRhdGEuZnJhbWUoc2NvcmVzKG5tZHMuMjAyMS5ibG9jay50cmFpdCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc19kYXRfMjAyMV9ibG9ja190cmFpdCA8LSBjYmluZChubWRzMSwgbm1kczIpICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgICMgRW5zdXJlIGl0J3MgYSBkYXRhIGZyYW1lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJzaXRlX2lkIikgJT4lICAjIE1vdmUgcm93IG5hbWVzIGludG8gYSBuZXcgY29sdW1uCiAgc2VwYXJhdGUoc2l0ZV9pZCwgaW50byA9IGMoIm51dF90cnQiLCAicHB0X3RydCIsICJ5ciIsICJncmF6aW5nX2hpc3QiKSwgc2VwID0gIl8iKQoKCiMgdHJhaXQgZGF0YTogdHJhaXRzLm1lYW5zLmNvbXAgCgoKIyB0cmFpdCB2ZWN0b3JzIG9udG8gdGhlIE5NRFMKdmVjdG9ycy5ubWRzLjIwMjEuYmxvY2sudHJhaXQgPC0KICBlbnZmaXQobm1kcy4yMDIxLmJsb2NrLnRyYWl0IH4gRHJ5TGVhZk1hc3MgKwogICAgICAgICAgIExlYWZBcmVhLCB0cmFpdHMubWVhbnMuY29tcCwgZGlzcGxheSA9ICJzcCIsIG5hLnJtID0gVFJVRSkKCiMgT05MWSBEcnlMZWFmTWFzcywgTGVhZkFyZWEKCnRyYWl0X3ZlY3RvcnMgPC0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuMjAyMS5ibG9jay50cmFpdCR2ZWN0b3JzJGFycm93cykKCmBgYAoKIyMjIyBQbG90CgpgYGB7cn0KZ2dwbG90KG5tZHNfZGF0XzIwMjFfYmxvY2tfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCwgY29sb3IgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChCbG9jaykgdyBUcmFpdHMgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopICsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gTk1EUzEsIHllbmQgPSBOTURTMiksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMg8J+agCBQcmV2ZW50cyBpdCBmcm9tIGxvb2tpbmcgZm9yICdudXRfdHJ0JwogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLCAKICAgIGNvbG9yID0gInJlZCIsIAogICAgc2l6ZSA9IDEKICApICsKICBnZW9tX3RleHQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIsIGxhYmVsID0gcm93bmFtZXModHJhaXRfdmVjdG9ycykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgpnZ3Bsb3Qobm1kc19kYXRfMjAyMV9ibG9ja190cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBwcHRfdHJ0LCBjb2xvciA9IHBwdF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrKSB3IFRyYWl0cyAtIEdyb3VwaW5nIGJ5IFByZWNpcGl0YXRpb24gVHJlYXRtZW50IikgKyAKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKSArCiAgZ2VvbV9zZWdtZW50KAogICAgZGF0YSA9IHRyYWl0X3ZlY3RvcnMsIAogICAgYWVzKHggPSAwLCB5ID0gMCwgeGVuZCA9IE5NRFMxLCB5ZW5kID0gTk1EUzIpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIPCfmoAgUHJldmVudHMgaXQgZnJvbSBsb29raW5nIGZvciAnbnV0X3RydCcKICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjIsICJjbSIpKSwgCiAgICBjb2xvciA9ICJyZWQiLCAKICAgIHNpemUgPSAxCiAgKSArCiAgZ2VvbV90ZXh0KAogICAgZGF0YSA9IHRyYWl0X3ZlY3RvcnMsIAogICAgYWVzKHggPSBOTURTMSwgeSA9IE5NRFMyLCBsYWJlbCA9IHJvd25hbWVzKHRyYWl0X3ZlY3RvcnMpKSwgCiAgICBpbmhlcml0LmFlcyA9IEZBTFNFLCAgIyBBdm9pZHMgdW53YW50ZWQgaW5oZXJpdGFuY2UKICAgIGhqdXN0ID0gLTAuMiwgCiAgICB2anVzdCA9IC0wLjIsIAogICAgY29sb3IgPSAicmVkIiwKICAgIHNpemUgPSA1CiAgKQpgYGAKCiMjIyAyMDIxIC0tIEJsb2NrcyAoTE9XKQoKU3RyZXNzOgoKYGBgICAgICAgICAgCjAuMTI5OTcxMQpgYGAKCiMjIyMgUHJlcGFyZSBOTURTIGFuZCBUcmFpdHMKCmBgYHtyfQojIHN1YnNldCBubWRzIHRvIG1hdGNoIHNwZWNpZXMgbmFtZXMKbm1kcy4yMDIxLmJsb2NrLmxvdy50cmFpdCA8LSBtZXRhTURTKG1hdHJpeC5icmF5LmJsb2NrLjIwMjEubG93ICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzZWxlY3QoaW50ZXJzZWN0Lm5hbWVzKSwgLCBrPTIsIHRyeW1heCA9IDI1KQpubWRzLjIwMjEuYmxvY2subG93LnRyYWl0IAoKbm1kczEgPC0gYXMuZGF0YS5mcmFtZShzY29yZXMobm1kcy4yMDIxLmJsb2NrLmxvdy50cmFpdCwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKQpubWRzMiA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEuYmxvY2subG93LnRyYWl0LCBjaG9pY2VzPWMoMiksIGRpc3BsYXk9Yygic2l0ZXMiKSkpCgpubWRzX2RhdF8yMDIxX2Jsb2NrX2xvd190cmFpdCA8LSBjYmluZChubWRzMSwgbm1kczIpICU+JQogIGFzLmRhdGEuZnJhbWUoKSAlPiUgICMgRW5zdXJlIGl0J3MgYSBkYXRhIGZyYW1lCiAgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJzaXRlX2lkIikgJT4lICAjIE1vdmUgcm93IG5hbWVzIGludG8gYSBuZXcgY29sdW1uCiAgc2VwYXJhdGUoc2l0ZV9pZCwgaW50byA9IGMoIm51dF90cnQiLCAicHB0X3RydCIsICJ5ciIsICJncmF6aW5nX2hpc3QiKSwgc2VwID0gIl8iKQoKCiMgdHJhaXQgZGF0YTogdHJhaXRzLm1lYW5zLmNvbXAgCgoKIyB0cmFpdCB2ZWN0b3JzIG9udG8gdGhlIE5NRFMKdmVjdG9ycy5ubWRzLjIwMjEuYmxvY2subG93LnRyYWl0IDwtCiAgZW52Zml0KG5tZHMuMjAyMS5ibG9jay5sb3cudHJhaXQgfiBGcmVzaExlYWZNYXNzLCB0cmFpdHMubWVhbnMuY29tcCwgZGlzcGxheSA9ICJzcCIsIG5hLnJtID0gVFJVRSkKCiMgT05MWSBGcmVzaExlYWZNYXNzCgp0cmFpdF92ZWN0b3JzIDwtIGFzLmRhdGEuZnJhbWUodmVjdG9ycy5ubWRzLjIwMjEuYmxvY2subG93LnRyYWl0JHZlY3RvcnMkYXJyb3dzKQpgYGAKCiMjIyMgUGxvdAoKYGBge3J9CmdncGxvdChubWRzX2RhdF8yMDIxX2Jsb2NrX2xvd190cmFpdCwgYWVzKE5NRFMxLCBOTURTMiwgIGZpbGwgPSBudXRfdHJ0LCBjb2xvciA9IG51dF90cnQpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBzaXplID0gNCwgc3Ryb2tlID0gMC41KSArIAogIGN1c3RvbV9jb2xvcnMgKyAKICBsYWJzKHRpdGxlID0gIjIwMjEgKEJsb2NrOyBMT1cpIHcgVHJhaXQgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopICsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gTk1EUzEsIHllbmQgPSBOTURTMiksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMg8J+agCBQcmV2ZW50cyBpdCBmcm9tIGxvb2tpbmcgZm9yICdudXRfdHJ0JwogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLCAKICAgIGNvbG9yID0gInJlZCIsIAogICAgc2l6ZSA9IDEKICApICsKICBnZW9tX3RleHQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIsIGxhYmVsID0gcm93bmFtZXModHJhaXRfdmVjdG9ycykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCgpnZ3Bsb3Qobm1kc19kYXRfMjAyMV9ibG9ja19sb3dfdHJhaXQsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCwgY29sb3IgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChCbG9jazsgTE9XKSB3IFRyYWl0IC0gR3JvdXBpbmcgYnkgUHJlY2lwaXRhdGlvbiBUcmVhdG1lbnQiKSArIAogIHN0YXRfZWxsaXBzZSh0eXBlID0gIm5vcm0iLCBzaXplID0gMSwgYWxwaGEgPSAwLjUpICsgIyBFbGxpcHNlcyBmb3IgZWFjaCBncm91cAogIHNjYWxlX2NvbG9yX21hbnVhbCgKICB2YWx1ZXMgPSBjKAogICAgImNvbnRyb2wiID0gcmdiKDIyMCwgMjIwLCAyMjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICMgTGlnaHRlciBHcmF5CiAgICAiK04gZmVydGlsaXplciIgPSByZ2IoMTQwLCA0MCwgMTUwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgIyBWaWJyYW50IFB1cnBsZQogICAgIitjb21wb3N0IiA9IHJnYigyMjAsIDE4MCwgNjAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAgICAgICAjIEJyaWdodCBHb2xkZW4gWWVsbG93CiAgICAid2V0IiA9IHJnYigwLCAwLCAyNTUsIG1heENvbG9yVmFsdWUgPSAyNTUpLAogICAgImRyeSIgPSByZ2IoMTgzLCA2NSwgMTQsIG1heENvbG9yVmFsdWUgPSAyNTUpCiAgKQopICsKICBnZW9tX3NlZ21lbnQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IDAsIHkgPSAwLCB4ZW5kID0gTk1EUzEsIHllbmQgPSBOTURTMiksIAogICAgaW5oZXJpdC5hZXMgPSBGQUxTRSwgICMg8J+agCBQcmV2ZW50cyBpdCBmcm9tIGxvb2tpbmcgZm9yICdudXRfdHJ0JwogICAgYXJyb3cgPSBhcnJvdyhsZW5ndGggPSB1bml0KDAuMiwgImNtIikpLCAKICAgIGNvbG9yID0gInJlZCIsIAogICAgc2l6ZSA9IDEKICApICsKICBnZW9tX3RleHQoCiAgICBkYXRhID0gdHJhaXRfdmVjdG9ycywgCiAgICBhZXMoeCA9IE5NRFMxLCB5ID0gTk1EUzIsIGxhYmVsID0gcm93bmFtZXModHJhaXRfdmVjdG9ycykpLCAKICAgIGluaGVyaXQuYWVzID0gRkFMU0UsICAjIEF2b2lkcyB1bndhbnRlZCBpbmhlcml0YW5jZQogICAgaGp1c3QgPSAtMC4yLCAKICAgIHZqdXN0ID0gLTAuMiwgCiAgICBjb2xvciA9ICJyZWQiLAogICAgc2l6ZSA9IDUKICApCmBgYAoKIyMjIDIwMjEgLS0gQmxvY2tzIChISUdIKQoKIyMjIyBQcmVwYXJlIE5NRFMgYW5kIFRyYWl0cwoKYGBge3J9CiMgc3Vic2V0IG5tZHMgdG8gbWF0Y2ggc3BlY2llcyBuYW1lcwpubWRzLjIwMjEuYmxvY2suaGlnaC50cmFpdCA8LSBtZXRhTURTKG1hdHJpeC5icmF5LmJsb2NrLjIwMjEuaGlnaCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcGx5cjo6c2VsZWN0KGludGVyc2VjdC5uYW1lcyksICwgaz0yLCB0cnltYXggPSAyNSkKbm1kcy4yMDIxLmJsb2NrLmhpZ2gudHJhaXQgCgpubWRzMSA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEuYmxvY2suaGlnaC50cmFpdCwgY2hvaWNlcz1jKDEpLCBkaXNwbGF5PWMoInNpdGVzIikpKQpubWRzMiA8LSBhcy5kYXRhLmZyYW1lKHNjb3JlcyhubWRzLjIwMjEuYmxvY2suaGlnaC50cmFpdCwgY2hvaWNlcz1jKDIpLCBkaXNwbGF5PWMoInNpdGVzIikpKQoKbm1kc19kYXRfMjAyMV9ibG9ja19oaWdoX3RyYWl0IDwtIGNiaW5kKG5tZHMxLCBubWRzMikgJT4lCiAgYXMuZGF0YS5mcmFtZSgpICU+JSAgIyBFbnN1cmUgaXQncyBhIGRhdGEgZnJhbWUKICByb3duYW1lc190b19jb2x1bW4odmFyID0gInNpdGVfaWQiKSAlPiUgICMgTW92ZSByb3cgbmFtZXMgaW50byBhIG5ldyBjb2x1bW4KICBzZXBhcmF0ZShzaXRlX2lkLCBpbnRvID0gYygibnV0X3RydCIsICJwcHRfdHJ0IiwgInlyIiwgImdyYXppbmdfaGlzdCIpLCBzZXAgPSAiXyIpCgoKIyB0cmFpdCBkYXRhOiB0cmFpdHMubWVhbnMuY29tcCAKCgojIHRyYWl0IHZlY3RvcnMgb250byB0aGUgTk1EUwp2ZWN0b3JzLm5tZHMuMjAyMS5ibG9jay5oaWdoLnRyYWl0IDwtCiAgZW52Zml0KG5tZHMuMjAyMS5ibG9jay5oaWdoLnRyYWl0IH4gSGVpZ2h0ICsgCiAgICAgICAgICAgRnJlc2hMZWFmTWFzcyArCiAgICAgICAgICAgRHJ5TGVhZk1hc3MgKwogICAgICAgICAgIExETUMgKwogICAgICAgICAgIExlYWZBcmVhICsKICAgICAgICAgICBTTEEgKwogICAgICAgICAgIFNob290RHJ5QmlvbWFzcyArCiAgICAgICAgICAgUm9vdERyeUJpb21hc3MgKwogICAgICAgICAgIFRvdGFsQmlvbWFzcyArCiAgICAgICAgICAgUk1GICsKICAgICAgICAgICBSb290Vm9sICsKICAgICAgICAgICBSb290RGVuc2l0eSArCiAgICAgICAgICAgQ29hcnNlUm9vdERpYW1ldGVyICsKICAgICAgICAgICBSb290TGVuZ3RoICsKICAgICAgICAgICBGaW5lUm9vdExlbmd0aCArCiAgICAgICAgICAgQ29hcnNlUm9vdExlbmd0aCArCiAgICAgICAgICAgQ29hcnNlUm9vdFNwZWNMZW5ndGggKwogICAgICAgICAgIEZpbmVSb290U3BlY0xlbmd0aCArCiAgICAgICAgICAgUHJvcEZpbmVSb290cywgdHJhaXRzLm1lYW5zLmNvbXAsIGRpc3BsYXkgPSAic3AiLCBuYS5ybSA9IFRSVUUpCgojIE5vbmUKCnRyYWl0X3ZlY3RvcnMgPC0gYXMuZGF0YS5mcmFtZSh2ZWN0b3JzLm5tZHMuMjAyMS5ibG9jay5oaWdoLnRyYWl0JHZlY3RvcnMkYXJyb3dzKQpgYGAKCiMjIyMgUGxvdAoKYGBge3J9CmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLmhpZ2gsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gbnV0X3RydCwgY29sb3IgPSBudXRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChCbG9jazsgSElHSCkgLSBHcm91cGluZyBieSBOdXRyaWVudCBUcmVhdG1lbnQiKSArCiAgc3RhdF9lbGxpcHNlKHR5cGUgPSAibm9ybSIsIHNpemUgPSAxLCBhbHBoYSA9IDAuNSkgKyAjIEVsbGlwc2VzIGZvciBlYWNoIGdyb3VwCiAgc2NhbGVfY29sb3JfbWFudWFsKAogIHZhbHVlcyA9IGMoCiAgICAiY29udHJvbCIgPSByZ2IoMjIwLCAyMjAsIDIyMCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgIyBMaWdodGVyIEdyYXkKICAgICIrTiBmZXJ0aWxpemVyIiA9IHJnYigxNDAsIDQwLCAxNTAsIG1heENvbG9yVmFsdWUgPSAyNTUpLCAjIFZpYnJhbnQgUHVycGxlCiAgICAiK2NvbXBvc3QiID0gcmdiKDIyMCwgMTgwLCA2MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICAgICAgICMgQnJpZ2h0IEdvbGRlbiBZZWxsb3cKICAgICJ3ZXQiID0gcmdiKDAsIDAsIDI1NSwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksCiAgICAiZHJ5IiA9IHJnYigxODMsIDY1LCAxNCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSkKICApCikKCmdncGxvdChubWRzXzIwMjFfZGF0LmJsb2NrLmhpZ2gsIGFlcyhOTURTMSwgTk1EUzIsICBmaWxsID0gcHB0X3RydCwgY29sb3IgPSBwcHRfdHJ0KSkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAyMSwgc2l6ZSA9IDQsIHN0cm9rZSA9IDAuNSkgKyAKICBjdXN0b21fY29sb3JzICsgCiAgbGFicyh0aXRsZSA9ICIyMDIxIChCbG9jazsgSElHSCkgLSBHcm91cGluZyBieSBQcmVjaXBpdGF0aW9uIFRyZWF0bWVudCIpICsKICBzdGF0X2VsbGlwc2UodHlwZSA9ICJub3JtIiwgc2l6ZSA9IDEsIGFscGhhID0gMC41KSArICMgRWxsaXBzZXMgZm9yIGVhY2ggZ3JvdXAKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgdmFsdWVzID0gYygKICAgICJjb250cm9sIiA9IHJnYigyMjAsIDIyMCwgMjIwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAjIExpZ2h0ZXIgR3JheQogICAgIitOIGZlcnRpbGl6ZXIiID0gcmdiKDE0MCwgNDAsIDE1MCwgbWF4Q29sb3JWYWx1ZSA9IDI1NSksICMgVmlicmFudCBQdXJwbGUKICAgICIrY29tcG9zdCIgPSByZ2IoMjIwLCAxODAsIDYwLCBtYXhDb2xvclZhbHVlID0gMjU1KSwgICAgICAgIyBCcmlnaHQgR29sZGVuIFllbGxvdwogICAgIndldCIgPSByZ2IoMCwgMCwgMjU1LCBtYXhDb2xvclZhbHVlID0gMjU1KSwKICAgICJkcnkiID0gcmdiKDE4MywgNjUsIDE0LCBtYXhDb2xvclZhbHVlID0gMjU1KQogICkKKQpgYGAK